WebBits 0.11.0 → 0.14.0
raw patch · 37 files changed
+2482/−3008 lines, 37 filessetup-changedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- WebBits.Common: class PrettyPrintable a
- WebBits.Common: data SourcePos :: *
- WebBits.Common: instance (PrettyPrintable a) => PrettyPrintable (Maybe a)
- WebBits.Common: instance Data SourcePos
- WebBits.Common: instance Typeable SourcePos
- WebBits.Common: isPrefixOf :: (Eq a) => [a] -> [a] -> Bool
- WebBits.Common: pp :: (PrettyPrintable a) => a -> Doc
- WebBits.Common: sourceName :: SourcePos -> SourceName
- WebBits.Data.Zipper: Node :: a -> Forest a -> Tree a
- WebBits.Data.Zipper: canGoDown :: Location a -> Bool
- WebBits.Data.Zipper: canGoLeft :: Location a -> Bool
- WebBits.Data.Zipper: canGoRight :: Location a -> Bool
- WebBits.Data.Zipper: canGoUp :: Location a -> Bool
- WebBits.Data.Zipper: change :: Location a -> a -> Location a
- WebBits.Data.Zipper: data Location a
- WebBits.Data.Zipper: data Tree a :: * -> *
- WebBits.Data.Zipper: dfsFold :: (w -> v -> w) -> w -> Tree v -> Tree w
- WebBits.Data.Zipper: dfsFoldM :: (Monad m) => (w -> v -> m w) -> w -> Tree v -> m (Tree w)
- WebBits.Data.Zipper: down :: Location a -> Location a
- WebBits.Data.Zipper: empty :: a -> Tree a
- WebBits.Data.Zipper: evalZipperT :: (Monad m) => ZipperT v m a -> Location v -> m a
- WebBits.Data.Zipper: execZipperT :: (Monad m) => ZipperT v m a -> Location v -> m (Tree v)
- WebBits.Data.Zipper: fromLocation :: Location a -> Tree a
- WebBits.Data.Zipper: getNode :: (Monad m) => ZipperT v m v
- WebBits.Data.Zipper: getValue :: Location a -> a
- WebBits.Data.Zipper: insertDown :: Location a -> Tree a -> Location a
- WebBits.Data.Zipper: insertLeft :: Location a -> Tree a -> Location a
- WebBits.Data.Zipper: insertRight :: Location a -> Tree a -> Location a
- WebBits.Data.Zipper: isChild :: Location a -> Bool
- WebBits.Data.Zipper: isTop :: Location a -> Bool
- WebBits.Data.Zipper: left :: Location a -> Location a
- WebBits.Data.Zipper: nest :: (Monad m) => v -> ZipperT v m a -> ZipperT v m a
- WebBits.Data.Zipper: replace :: Location a -> Tree a -> Location a
- WebBits.Data.Zipper: right :: Location a -> Location a
- WebBits.Data.Zipper: rootLabel :: Tree a -> a
- WebBits.Data.Zipper: runZipperT :: (Monad m) => ZipperT v m a -> Location v -> m (a, Tree v)
- WebBits.Data.Zipper: setNode :: (Monad m) => v -> ZipperT v m ()
- WebBits.Data.Zipper: shiftLeft :: (Monad m) => ZipperT v m ()
- WebBits.Data.Zipper: shiftLeft' :: (Monad m) => ZipperT v m ()
- WebBits.Data.Zipper: shiftRight :: (Monad m) => ZipperT v m ()
- WebBits.Data.Zipper: shiftRight' :: (Monad m) => ZipperT v m ()
- WebBits.Data.Zipper: showTree :: (Show a) => Tree a -> String
- WebBits.Data.Zipper: subForest :: Tree a -> Forest a
- WebBits.Data.Zipper: subTree :: Location a -> Tree a
- WebBits.Data.Zipper: toLocation :: Tree a -> Location a
- WebBits.Data.Zipper: top :: Location a -> Location a
- WebBits.Data.Zipper: type ZipperT v m a = StateT (Location v) m a
- WebBits.Data.Zipper: up :: Location a -> Location a
- WebBits.Data.Zipper: withCurrentChild :: (Monad m) => ZipperT v m a -> ZipperT v m a
- WebBits.Html.Html: html :: (Script s) => CharParser [Warning] (Html SourcePos s)
- WebBits.Html.Html: parseHtmlFromFile :: (Script s) => String -> IO (Either ParseError (Html SourcePos s, [Warning]))
- WebBits.Html.Html: parseHtmlFromString :: (Script s) => String -> String -> Either ParseError (Html SourcePos s, [Warning])
- WebBits.Html.Instances: instance Foldable (Attribute a)
- WebBits.Html.Instances: instance Foldable (Html a)
- WebBits.Html.Instances: instance Functor (Attribute a)
- WebBits.Html.Instances: instance Functor (Html a)
- WebBits.Html.Instances: instance Traversable (Attribute a)
- WebBits.Html.Instances: instance Traversable (Html a)
- WebBits.Html.PermissiveParser: data (Script s) => Token s
- WebBits.Html.PermissiveParser: html :: (Script s) => CharParser [Warning] (Html SourcePos s)
- WebBits.Html.PermissiveParser: instance (Script s) => Show (Token s)
- WebBits.Html.PermissiveParser: instance Show Warning
- WebBits.Html.PermissiveParser: parseHtmlFromFile :: (Script s) => String -> IO (Either ParseError (Html SourcePos s, [Warning]))
- WebBits.Html.PermissiveParser: parseHtmlFromString :: (Script s) => String -> String -> Either ParseError (Html SourcePos s, [Warning])
- WebBits.Html.PermissiveParser: tokens :: (Script s) => CharParser [Warning] [Token s]
- WebBits.Html.PrettyPrint: instance (PrettyPrintable s) => PrettyPrintable (Attribute a s)
- WebBits.Html.PrettyPrint: instance (PrettyPrintable s) => PrettyPrintable (Html a s)
- WebBits.Html.RawScript: RawScript :: String -> RawScript
- WebBits.Html.RawScript: data RawScript
- WebBits.Html.RawScript: instance Data RawScript
- WebBits.Html.RawScript: instance Eq RawScript
- WebBits.Html.RawScript: instance PrettyPrintable RawScript
- WebBits.Html.RawScript: instance Script RawScript
- WebBits.Html.RawScript: instance Show RawScript
- WebBits.Html.RawScript: instance Typeable RawScript
- WebBits.Html.RawScript: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
- WebBits.Html.RawScript: parseFromString :: String -> RawHtml
- WebBits.Html.RawScript: type RawHtml = Html SourcePos RawScript
- WebBits.Html.Syntax: Attribute :: HtmlId -> AttributeValue -> a -> Attribute a s
- WebBits.Html.Syntax: AttributeExpr :: a -> HtmlId -> s -> String -> Attribute a s
- WebBits.Html.Syntax: Comment :: String -> a -> Html a sc
- WebBits.Html.Syntax: Element :: HtmlId -> [Attribute a sc] -> [Html a sc] -> a -> Html a sc
- WebBits.Html.Syntax: HtmlSeq :: [Html a sc] -> Html a sc
- WebBits.Html.Syntax: InlineScript :: sc -> a -> String -> Html a sc
- WebBits.Html.Syntax: ProcessingInstruction :: String -> a -> Html a sc
- WebBits.Html.Syntax: Script :: sc -> a -> Html a sc
- WebBits.Html.Syntax: Text :: String -> a -> Html a sc
- WebBits.Html.Syntax: attributeSet :: HtmlId -> String -> [Attribute a s] -> [Attribute a s]
- WebBits.Html.Syntax: attributeUpdate :: HtmlId -> (String -> String) -> [Attribute a s] -> [Attribute a s]
- WebBits.Html.Syntax: attributeValue :: HtmlId -> [Attribute a s] -> Maybe String
- WebBits.Html.Syntax: class Script t
- WebBits.Html.Syntax: data Attribute a s
- WebBits.Html.Syntax: data Html a sc
- WebBits.Html.Syntax: instance (Data a, Data s) => Data (Attribute a s)
- WebBits.Html.Syntax: instance (Data a, Data sc) => Data (Html a sc)
- WebBits.Html.Syntax: instance (Eq a, Eq s) => Eq (Attribute a s)
- WebBits.Html.Syntax: instance (Eq a, Eq sc) => Eq (Html a sc)
- WebBits.Html.Syntax: instance (Show a, Show s) => Show (Attribute a s)
- WebBits.Html.Syntax: instance (Show a, Show sc) => Show (Html a sc)
- WebBits.Html.Syntax: instance Typeable2 Attribute
- WebBits.Html.Syntax: instance Typeable2 Html
- WebBits.Html.Syntax: isAttributeExpr :: Attribute t t1 -> Bool
- WebBits.Html.Syntax: parseAttributeScript :: (Script t) => Maybe (CharParser a t)
- WebBits.Html.Syntax: parseInlineScript :: (Script t) => Maybe (CharParser a t)
- WebBits.Html.Syntax: parseScriptBlock :: (Script t) => [Attribute SourcePos t] -> CharParser a t
- WebBits.Html.Syntax: type AttributeValue = String
- WebBits.Html.Syntax: type HtmlId = String
- WebBits.JavaScript.Combinators: expressionsAt :: (Data a, Typeable a) => SourcePos -> a -> [Expression SourcePos]
- WebBits.JavaScript.Combinators: isParenExpr :: Expression t -> Bool
- WebBits.JavaScript.Combinators: scriptStatements :: JavaScript a -> [Statement a]
- WebBits.JavaScript.Combinators: statementsAt :: (Data a, Typeable a) => SourcePos -> a -> [Statement SourcePos]
- WebBits.JavaScript.Combinators: syntaxAt :: (Data a, Typeable a, Data (t SourcePos), Typeable (t SourcePos), Foldable t) => SourcePos -> a -> [t SourcePos]
- WebBits.JavaScript.Crawl: getPageJavaScript :: ParsedJsHtml -> IO [ParsedStatement]
- WebBits.JavaScript.Environment: staticEnvironment :: [Statement SourcePos] -> ([Statement Ann], Env, Env, Int)
- WebBits.JavaScript.Environment: type Ann = (Env, Int, SourcePos)
- WebBits.JavaScript.Environment: type Env = Map String Int
- WebBits.JavaScript.Environment: type LabelledExpression = Expression Ann
- WebBits.JavaScript.Environment: type LabelledStatement = Statement Ann
- WebBits.JavaScript.HtmlEmbedding: instance Script ParsedJavaScript
- WebBits.JavaScript.HtmlEmbedding: type JsHtml a = Html SourcePos (JavaScript a)
- WebBits.JavaScript.HtmlEmbedding: type ParsedJavaScript = JavaScript SourcePos
- WebBits.JavaScript.HtmlEmbedding: type ParsedJsHtml = JsHtml SourcePos
- WebBits.JavaScript.Instances: instance Foldable CaseClause
- WebBits.JavaScript.Instances: instance Foldable CatchClause
- WebBits.JavaScript.Instances: instance Foldable Expression
- WebBits.JavaScript.Instances: instance Foldable ForInInit
- WebBits.JavaScript.Instances: instance Foldable ForInit
- WebBits.JavaScript.Instances: instance Foldable Id
- WebBits.JavaScript.Instances: instance Foldable Prop
- WebBits.JavaScript.Instances: instance Foldable Statement
- WebBits.JavaScript.Instances: instance Foldable VarDecl
- WebBits.JavaScript.Instances: instance Functor CaseClause
- WebBits.JavaScript.Instances: instance Functor CatchClause
- WebBits.JavaScript.Instances: instance Functor Expression
- WebBits.JavaScript.Instances: instance Functor ForInInit
- WebBits.JavaScript.Instances: instance Functor ForInit
- WebBits.JavaScript.Instances: instance Functor Id
- WebBits.JavaScript.Instances: instance Functor JavaScript
- WebBits.JavaScript.Instances: instance Functor Prop
- WebBits.JavaScript.Instances: instance Functor Statement
- WebBits.JavaScript.Instances: instance Functor VarDecl
- WebBits.JavaScript.Instances: instance Traversable CaseClause
- WebBits.JavaScript.Instances: instance Traversable CatchClause
- WebBits.JavaScript.Instances: instance Traversable Expression
- WebBits.JavaScript.Instances: instance Traversable ForInInit
- WebBits.JavaScript.Instances: instance Traversable ForInit
- WebBits.JavaScript.Instances: instance Traversable Id
- WebBits.JavaScript.Instances: instance Traversable Prop
- WebBits.JavaScript.Instances: instance Traversable Statement
- WebBits.JavaScript.Instances: instance Traversable VarDecl
- WebBits.JavaScript.Lexer: braces :: CharParser st a -> CharParser st a
- WebBits.JavaScript.Lexer: brackets :: CharParser st a -> CharParser st a
- WebBits.JavaScript.Lexer: charLiteral :: CharParser st Char
- WebBits.JavaScript.Lexer: colon :: CharParser st String
- WebBits.JavaScript.Lexer: comma :: CharParser st String
- WebBits.JavaScript.Lexer: decimal :: CharParser st Integer
- WebBits.JavaScript.Lexer: dot :: CharParser st String
- WebBits.JavaScript.Lexer: float :: CharParser st Double
- WebBits.JavaScript.Lexer: hexadecimal :: CharParser st Integer
- WebBits.JavaScript.Lexer: identifier :: CharParser st String
- WebBits.JavaScript.Lexer: identifierStart :: GenParser Char st Char
- WebBits.JavaScript.Lexer: integer :: CharParser st Integer
- WebBits.JavaScript.Lexer: lexeme :: CharParser st a -> CharParser st a
- WebBits.JavaScript.Lexer: natural :: CharParser st Integer
- WebBits.JavaScript.Lexer: naturalOrFloat :: CharParser st (Either Integer Double)
- WebBits.JavaScript.Lexer: octal :: CharParser st Integer
- WebBits.JavaScript.Lexer: operator :: CharParser st String
- WebBits.JavaScript.Lexer: parens :: CharParser st a -> CharParser st a
- WebBits.JavaScript.Lexer: reserved :: String -> CharParser st ()
- WebBits.JavaScript.Lexer: reservedOp :: String -> CharParser st ()
- WebBits.JavaScript.Lexer: semi :: CharParser st String
- WebBits.JavaScript.Lexer: squares :: CharParser st a -> CharParser st a
- WebBits.JavaScript.Lexer: stringLiteral :: CharParser st String
- WebBits.JavaScript.Lexer: symbol :: String -> CharParser st String
- WebBits.JavaScript.Lexer: whiteSpace :: CharParser st ()
- WebBits.JavaScript.Parser: emptyParsedJavaScript :: JavaScript a
- WebBits.JavaScript.Parser: parseAssignExpr :: ExpressionParser st
- WebBits.JavaScript.Parser: parseBlockStmt :: StatementParser st
- WebBits.JavaScript.Parser: parseExpression :: ExpressionParser st
- WebBits.JavaScript.Parser: parseJavaScriptFromFile :: (MonadIO m) => String -> m [Statement SourcePos]
- WebBits.JavaScript.Parser: parseScript :: CharParser state (JavaScript SourcePos)
- WebBits.JavaScript.Parser: parseScriptFromString :: String -> String -> Either ParseError (JavaScript SourcePos)
- WebBits.JavaScript.Parser: parseSimpleExpr' :: GenParser Char st ParsedExpression
- WebBits.JavaScript.Parser: parseStatement :: StatementParser st
- WebBits.JavaScript.Parser: parseString :: String -> [Statement SourcePos]
- WebBits.JavaScript.Parser: type ExpressionParser state = CharParser state ParsedExpression
- WebBits.JavaScript.Parser: type ParsedExpression = Expression SourcePos
- WebBits.JavaScript.Parser: type ParsedStatement = Statement SourcePos
- WebBits.JavaScript.Parser: type StatementParser state = CharParser state ParsedStatement
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (CaseClause a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (CatchClause a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (Expression a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (ForInInit a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (ForInit a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (Id a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (JavaScript a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (Prop a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (Statement a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable (VarDecl a)
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable AssignOp
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable InfixOp
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable PostfixOp
- WebBits.JavaScript.PrettyPrint: instance PrettyPrintable PrefixOp
- WebBits.JavaScript.Syntax: ArrayLit :: a -> [Expression a] -> Expression a
- WebBits.JavaScript.Syntax: AssignExpr :: a -> AssignOp -> (Expression a) -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: BlockStmt :: a -> [Statement a] -> Statement a
- WebBits.JavaScript.Syntax: BoolLit :: a -> Bool -> Expression a
- WebBits.JavaScript.Syntax: BracketRef :: a -> (Expression a) -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: BreakStmt :: a -> (Maybe (Id a)) -> Statement a
- WebBits.JavaScript.Syntax: CallExpr :: a -> (Expression a) -> [Expression a] -> Expression a
- WebBits.JavaScript.Syntax: CaseClause :: a -> (Expression a) -> [Statement a] -> CaseClause a
- WebBits.JavaScript.Syntax: CaseDefault :: a -> [Statement a] -> CaseClause a
- WebBits.JavaScript.Syntax: CatchClause :: a -> (Id a) -> (Statement a) -> CatchClause a
- WebBits.JavaScript.Syntax: CondExpr :: a -> (Expression a) -> (Expression a) -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: ContinueStmt :: a -> (Maybe (Id a)) -> Statement a
- WebBits.JavaScript.Syntax: DoWhileStmt :: a -> (Statement a) -> (Expression a) -> Statement a
- WebBits.JavaScript.Syntax: DotRef :: a -> (Expression a) -> (Id a) -> Expression a
- WebBits.JavaScript.Syntax: EmptyStmt :: a -> Statement a
- WebBits.JavaScript.Syntax: ExprInit :: (Expression a) -> ForInit a
- WebBits.JavaScript.Syntax: ExprStmt :: a -> (Expression a) -> Statement a
- WebBits.JavaScript.Syntax: ForInNoVar :: (Id a) -> ForInInit a
- WebBits.JavaScript.Syntax: ForInStmt :: a -> (ForInInit a) -> (Expression a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: ForInVar :: (Id a) -> ForInInit a
- WebBits.JavaScript.Syntax: ForStmt :: a -> (ForInit a) -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: FuncExpr :: a -> [(Id a)] -> (Statement a) -> Expression a
- WebBits.JavaScript.Syntax: FunctionStmt :: a -> (Id a) -> [(Id a)] -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: Id :: a -> String -> Id a
- WebBits.JavaScript.Syntax: IfSingleStmt :: a -> (Expression a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: IfStmt :: a -> (Expression a) -> (Statement a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: InfixExpr :: a -> InfixOp -> (Expression a) -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: LabelledStmt :: a -> (Id a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: ListExpr :: a -> [Expression a] -> Expression a
- WebBits.JavaScript.Syntax: NewExpr :: a -> (Expression a) -> [Expression a] -> Expression a
- WebBits.JavaScript.Syntax: NoInit :: ForInit a
- WebBits.JavaScript.Syntax: NullLit :: a -> Expression a
- WebBits.JavaScript.Syntax: NumLit :: a -> Double -> Expression a
- WebBits.JavaScript.Syntax: ObjectLit :: a -> [(Prop a, Expression a)] -> Expression a
- WebBits.JavaScript.Syntax: OpAdd :: InfixOp
- WebBits.JavaScript.Syntax: OpAssign :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignAdd :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignBAnd :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignBOr :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignBXor :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignDiv :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignLShift :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignMod :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignMul :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignSpRShift :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignSub :: AssignOp
- WebBits.JavaScript.Syntax: OpAssignZfRShift :: AssignOp
- WebBits.JavaScript.Syntax: OpBAnd :: InfixOp
- WebBits.JavaScript.Syntax: OpBOr :: InfixOp
- WebBits.JavaScript.Syntax: OpBXor :: InfixOp
- WebBits.JavaScript.Syntax: OpDiv :: InfixOp
- WebBits.JavaScript.Syntax: OpEq :: InfixOp
- WebBits.JavaScript.Syntax: OpGEq :: InfixOp
- WebBits.JavaScript.Syntax: OpGT :: InfixOp
- WebBits.JavaScript.Syntax: OpIn :: InfixOp
- WebBits.JavaScript.Syntax: OpInstanceof :: InfixOp
- WebBits.JavaScript.Syntax: OpLAnd :: InfixOp
- WebBits.JavaScript.Syntax: OpLEq :: InfixOp
- WebBits.JavaScript.Syntax: OpLOr :: InfixOp
- WebBits.JavaScript.Syntax: OpLShift :: InfixOp
- WebBits.JavaScript.Syntax: OpLT :: InfixOp
- WebBits.JavaScript.Syntax: OpMod :: InfixOp
- WebBits.JavaScript.Syntax: OpMul :: InfixOp
- WebBits.JavaScript.Syntax: OpNEq :: InfixOp
- WebBits.JavaScript.Syntax: OpSpRShift :: InfixOp
- WebBits.JavaScript.Syntax: OpStrictEq :: InfixOp
- WebBits.JavaScript.Syntax: OpStrictNEq :: InfixOp
- WebBits.JavaScript.Syntax: OpSub :: InfixOp
- WebBits.JavaScript.Syntax: OpZfRShift :: InfixOp
- WebBits.JavaScript.Syntax: ParenExpr :: a -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: PostfixDec :: PostfixOp
- WebBits.JavaScript.Syntax: PostfixExpr :: a -> PostfixOp -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: PostfixInc :: PostfixOp
- WebBits.JavaScript.Syntax: PrefixBNot :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixDec :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixDelete :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixExpr :: a -> PrefixOp -> (Expression a) -> Expression a
- WebBits.JavaScript.Syntax: PrefixInc :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixLNot :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixMinus :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixPlus :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixTypeof :: PrefixOp
- WebBits.JavaScript.Syntax: PrefixVoid :: PrefixOp
- WebBits.JavaScript.Syntax: PropId :: a -> (Id a) -> Prop a
- WebBits.JavaScript.Syntax: PropNum :: a -> Integer -> Prop a
- WebBits.JavaScript.Syntax: PropString :: a -> String -> Prop a
- WebBits.JavaScript.Syntax: RegexpLit :: a -> String -> Bool -> Bool -> Expression a
- WebBits.JavaScript.Syntax: ReturnStmt :: a -> (Maybe (Expression a)) -> Statement a
- WebBits.JavaScript.Syntax: Script :: a -> [Statement a] -> JavaScript a
- WebBits.JavaScript.Syntax: StringLit :: a -> String -> Expression a
- WebBits.JavaScript.Syntax: SwitchStmt :: a -> (Expression a) -> [CaseClause a] -> Statement a
- WebBits.JavaScript.Syntax: ThisRef :: a -> Expression a
- WebBits.JavaScript.Syntax: ThrowStmt :: a -> (Expression a) -> Statement a
- WebBits.JavaScript.Syntax: TryStmt :: a -> (Statement a) -> [CatchClause a] -> (Maybe (Statement a)) -> Statement a
- WebBits.JavaScript.Syntax: VarDecl :: a -> (Id a) -> (Maybe (Expression a)) -> VarDecl a
- WebBits.JavaScript.Syntax: VarDeclStmt :: a -> [VarDecl a] -> Statement a
- WebBits.JavaScript.Syntax: VarInit :: [VarDecl a] -> ForInit a
- WebBits.JavaScript.Syntax: VarRef :: a -> (Id a) -> Expression a
- WebBits.JavaScript.Syntax: WhileStmt :: a -> (Expression a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: WithStmt :: a -> (Expression a) -> (Statement a) -> Statement a
- WebBits.JavaScript.Syntax: data AssignOp
- WebBits.JavaScript.Syntax: data CaseClause a
- WebBits.JavaScript.Syntax: data CatchClause a
- WebBits.JavaScript.Syntax: data Expression a
- WebBits.JavaScript.Syntax: data ForInInit a
- WebBits.JavaScript.Syntax: data ForInit a
- WebBits.JavaScript.Syntax: data Id a
- WebBits.JavaScript.Syntax: data InfixOp
- WebBits.JavaScript.Syntax: data JavaScript a
- WebBits.JavaScript.Syntax: data PostfixOp
- WebBits.JavaScript.Syntax: data PrefixOp
- WebBits.JavaScript.Syntax: data Prop a
- WebBits.JavaScript.Syntax: data Statement a
- WebBits.JavaScript.Syntax: data VarDecl a
- WebBits.JavaScript.Syntax: instance (Data a) => Data (CaseClause a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (CatchClause a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (Expression a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (ForInInit a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (ForInit a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (Id a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (JavaScript a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (Prop a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (Statement a)
- WebBits.JavaScript.Syntax: instance (Data a) => Data (VarDecl a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (CaseClause a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (CatchClause a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (Expression a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (ForInInit a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (ForInit a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (Id a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (JavaScript a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (Prop a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (Statement a)
- WebBits.JavaScript.Syntax: instance (Eq a) => Eq (VarDecl a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (CaseClause a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (CatchClause a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (Expression a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (ForInInit a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (ForInit a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (Id a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (JavaScript a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (Prop a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (Statement a)
- WebBits.JavaScript.Syntax: instance (Ord a) => Ord (VarDecl a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (CaseClause a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (CatchClause a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (Expression a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (ForInInit a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (ForInit a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (Id a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (JavaScript a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (Prop a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (Statement a)
- WebBits.JavaScript.Syntax: instance (Show a) => Show (VarDecl a)
- WebBits.JavaScript.Syntax: instance Data AssignOp
- WebBits.JavaScript.Syntax: instance Data InfixOp
- WebBits.JavaScript.Syntax: instance Data PostfixOp
- WebBits.JavaScript.Syntax: instance Data PrefixOp
- WebBits.JavaScript.Syntax: instance Enum InfixOp
- WebBits.JavaScript.Syntax: instance Eq AssignOp
- WebBits.JavaScript.Syntax: instance Eq InfixOp
- WebBits.JavaScript.Syntax: instance Eq PostfixOp
- WebBits.JavaScript.Syntax: instance Eq PrefixOp
- WebBits.JavaScript.Syntax: instance Ord AssignOp
- WebBits.JavaScript.Syntax: instance Ord InfixOp
- WebBits.JavaScript.Syntax: instance Ord PostfixOp
- WebBits.JavaScript.Syntax: instance Ord PrefixOp
- WebBits.JavaScript.Syntax: instance Show AssignOp
- WebBits.JavaScript.Syntax: instance Show InfixOp
- WebBits.JavaScript.Syntax: instance Show PostfixOp
- WebBits.JavaScript.Syntax: instance Show PrefixOp
- WebBits.JavaScript.Syntax: instance Typeable AssignOp
- WebBits.JavaScript.Syntax: instance Typeable InfixOp
- WebBits.JavaScript.Syntax: instance Typeable PostfixOp
- WebBits.JavaScript.Syntax: instance Typeable PrefixOp
- WebBits.JavaScript.Syntax: instance Typeable1 CaseClause
- WebBits.JavaScript.Syntax: instance Typeable1 CatchClause
- WebBits.JavaScript.Syntax: instance Typeable1 Expression
- WebBits.JavaScript.Syntax: instance Typeable1 ForInInit
- WebBits.JavaScript.Syntax: instance Typeable1 ForInit
- WebBits.JavaScript.Syntax: instance Typeable1 Id
- WebBits.JavaScript.Syntax: instance Typeable1 JavaScript
- WebBits.JavaScript.Syntax: instance Typeable1 Prop
- WebBits.JavaScript.Syntax: instance Typeable1 Statement
- WebBits.JavaScript.Syntax: instance Typeable1 VarDecl
+ BrownPLT.Html: parseHtmlFromFile :: (Script s) => String -> IO (Either ParseError (Html SourcePos s, [Warning]))
+ BrownPLT.Html: parseHtmlFromString :: (Script s) => String -> String -> Either ParseError (Html SourcePos s, [Warning])
+ BrownPLT.Html: renderHtml :: (Script s) => Html a s -> String
+ BrownPLT.Html.Instances: instance Foldable (Attribute a)
+ BrownPLT.Html.Instances: instance Foldable (Html a)
+ BrownPLT.Html.Instances: instance Functor (Attribute a)
+ BrownPLT.Html.Instances: instance Functor (Html a)
+ BrownPLT.Html.Instances: instance Traversable (Attribute a)
+ BrownPLT.Html.Instances: instance Traversable (Html a)
+ BrownPLT.Html.PermissiveParser: data (Script s) => Token s
+ BrownPLT.Html.PermissiveParser: html :: (Script s) => CharParser [Warning] (Html SourcePos s)
+ BrownPLT.Html.PermissiveParser: instance (Script s) => Show (Token s)
+ BrownPLT.Html.PermissiveParser: instance Show Warning
+ BrownPLT.Html.PermissiveParser: parseHtmlFromFile :: (Script s) => String -> IO (Either ParseError (Html SourcePos s, [Warning]))
+ BrownPLT.Html.PermissiveParser: parseHtmlFromString :: (Script s) => String -> String -> Either ParseError (Html SourcePos s, [Warning])
+ BrownPLT.Html.PermissiveParser: tokens :: (Script s) => CharParser [Warning] [Token s]
+ BrownPLT.Html.PrettyPrint: html :: (Script s) => Html a s -> Doc
+ BrownPLT.Html.PrettyPrint: renderHtml :: (Script s) => Html a s -> String
+ BrownPLT.Html.RawScript: RawScript :: String -> RawScript
+ BrownPLT.Html.RawScript: data RawScript
+ BrownPLT.Html.RawScript: instance Data RawScript
+ BrownPLT.Html.RawScript: instance Eq RawScript
+ BrownPLT.Html.RawScript: instance Script RawScript
+ BrownPLT.Html.RawScript: instance Show RawScript
+ BrownPLT.Html.RawScript: instance Typeable RawScript
+ BrownPLT.Html.RawScript: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
+ BrownPLT.Html.RawScript: parseFromString :: String -> RawHtml
+ BrownPLT.Html.RawScript: type RawHtml = Html SourcePos RawScript
+ BrownPLT.Html.Syntax: Attribute :: HtmlId -> AttributeValue -> a -> Attribute a s
+ BrownPLT.Html.Syntax: AttributeExpr :: a -> HtmlId -> s -> String -> Attribute a s
+ BrownPLT.Html.Syntax: Comment :: String -> a -> Html a sc
+ BrownPLT.Html.Syntax: Element :: HtmlId -> [Attribute a sc] -> [Html a sc] -> a -> Html a sc
+ BrownPLT.Html.Syntax: HtmlSeq :: [Html a sc] -> Html a sc
+ BrownPLT.Html.Syntax: InlineScript :: sc -> a -> String -> Html a sc
+ BrownPLT.Html.Syntax: ProcessingInstruction :: String -> a -> Html a sc
+ BrownPLT.Html.Syntax: Script :: sc -> a -> Html a sc
+ BrownPLT.Html.Syntax: Text :: String -> a -> Html a sc
+ BrownPLT.Html.Syntax: attributeSet :: HtmlId -> String -> [Attribute a s] -> [Attribute a s]
+ BrownPLT.Html.Syntax: attributeUpdate :: HtmlId -> (String -> String) -> [Attribute a s] -> [Attribute a s]
+ BrownPLT.Html.Syntax: attributeValue :: HtmlId -> [Attribute a s] -> Maybe String
+ BrownPLT.Html.Syntax: class Script t
+ BrownPLT.Html.Syntax: data Attribute a s
+ BrownPLT.Html.Syntax: data Html a sc
+ BrownPLT.Html.Syntax: instance (Data a, Data s) => Data (Attribute a s)
+ BrownPLT.Html.Syntax: instance (Data a, Data sc) => Data (Html a sc)
+ BrownPLT.Html.Syntax: instance (Eq a, Eq s) => Eq (Attribute a s)
+ BrownPLT.Html.Syntax: instance (Eq a, Eq sc) => Eq (Html a sc)
+ BrownPLT.Html.Syntax: instance (Show a, Show s) => Show (Attribute a s)
+ BrownPLT.Html.Syntax: instance (Show a, Show sc) => Show (Html a sc)
+ BrownPLT.Html.Syntax: instance Typeable2 Attribute
+ BrownPLT.Html.Syntax: instance Typeable2 Html
+ BrownPLT.Html.Syntax: isAttributeExpr :: Attribute t t1 -> Bool
+ BrownPLT.Html.Syntax: parseAttributeScript :: (Script t) => Maybe (CharParser a t)
+ BrownPLT.Html.Syntax: parseInlineScript :: (Script t) => Maybe (CharParser a t)
+ BrownPLT.Html.Syntax: parseScriptBlock :: (Script t) => [Attribute SourcePos t] -> CharParser a t
+ BrownPLT.Html.Syntax: prettyPrintScript :: (Script t) => t -> Doc
+ BrownPLT.Html.Syntax: type AttributeValue = String
+ BrownPLT.Html.Syntax: type HtmlId = String
+ BrownPLT.JavaScript: renderExpression :: Expression a -> String
+ BrownPLT.JavaScript: renderStatements :: [Statement a] -> String
+ BrownPLT.JavaScript.Crawl: getPageJavaScript :: ParsedJsHtml -> IO [ParsedStatement]
+ BrownPLT.JavaScript.Crawl: instance Data SourcePos
+ BrownPLT.JavaScript.Crawl: instance Typeable SourcePos
+ BrownPLT.JavaScript.Environment: EnvTree :: (Map String SourcePos) -> [EnvTree] -> EnvTree
+ BrownPLT.JavaScript.Environment: data EnvTree
+ BrownPLT.JavaScript.Environment: env :: Map String SourcePos -> [Statement SourcePos] -> (EnvTree, Map String SourcePos)
+ BrownPLT.JavaScript.Environment: localVars :: [Statement SourcePos] -> Set String
+ BrownPLT.JavaScript.HtmlEmbedding: instance Script ParsedJavaScript
+ BrownPLT.JavaScript.HtmlEmbedding: type JsHtml a = Html SourcePos (JavaScript a)
+ BrownPLT.JavaScript.HtmlEmbedding: type ParsedJavaScript = JavaScript SourcePos
+ BrownPLT.JavaScript.HtmlEmbedding: type ParsedJsHtml = JsHtml SourcePos
+ BrownPLT.JavaScript.Instances: instance Foldable CaseClause
+ BrownPLT.JavaScript.Instances: instance Foldable CatchClause
+ BrownPLT.JavaScript.Instances: instance Foldable Expression
+ BrownPLT.JavaScript.Instances: instance Foldable ForInInit
+ BrownPLT.JavaScript.Instances: instance Foldable ForInit
+ BrownPLT.JavaScript.Instances: instance Foldable Id
+ BrownPLT.JavaScript.Instances: instance Foldable Prop
+ BrownPLT.JavaScript.Instances: instance Foldable Statement
+ BrownPLT.JavaScript.Instances: instance Foldable VarDecl
+ BrownPLT.JavaScript.Instances: instance Functor CaseClause
+ BrownPLT.JavaScript.Instances: instance Functor CatchClause
+ BrownPLT.JavaScript.Instances: instance Functor Expression
+ BrownPLT.JavaScript.Instances: instance Functor ForInInit
+ BrownPLT.JavaScript.Instances: instance Functor ForInit
+ BrownPLT.JavaScript.Instances: instance Functor Id
+ BrownPLT.JavaScript.Instances: instance Functor JavaScript
+ BrownPLT.JavaScript.Instances: instance Functor Prop
+ BrownPLT.JavaScript.Instances: instance Functor Statement
+ BrownPLT.JavaScript.Instances: instance Functor VarDecl
+ BrownPLT.JavaScript.Instances: instance Traversable CaseClause
+ BrownPLT.JavaScript.Instances: instance Traversable CatchClause
+ BrownPLT.JavaScript.Instances: instance Traversable Expression
+ BrownPLT.JavaScript.Instances: instance Traversable ForInInit
+ BrownPLT.JavaScript.Instances: instance Traversable ForInit
+ BrownPLT.JavaScript.Instances: instance Traversable Id
+ BrownPLT.JavaScript.Instances: instance Traversable Prop
+ BrownPLT.JavaScript.Instances: instance Traversable Statement
+ BrownPLT.JavaScript.Instances: instance Traversable VarDecl
+ BrownPLT.JavaScript.Lexer: braces :: CharParser st a -> CharParser st a
+ BrownPLT.JavaScript.Lexer: brackets :: CharParser st a -> CharParser st a
+ BrownPLT.JavaScript.Lexer: charLiteral :: CharParser st Char
+ BrownPLT.JavaScript.Lexer: colon :: CharParser st String
+ BrownPLT.JavaScript.Lexer: comma :: CharParser st String
+ BrownPLT.JavaScript.Lexer: decimal :: CharParser st Integer
+ BrownPLT.JavaScript.Lexer: dot :: CharParser st String
+ BrownPLT.JavaScript.Lexer: float :: CharParser st Double
+ BrownPLT.JavaScript.Lexer: hexadecimal :: CharParser st Integer
+ BrownPLT.JavaScript.Lexer: identifier :: CharParser st String
+ BrownPLT.JavaScript.Lexer: identifierStart :: GenParser Char st Char
+ BrownPLT.JavaScript.Lexer: integer :: CharParser st Integer
+ BrownPLT.JavaScript.Lexer: lexeme :: CharParser st a -> CharParser st a
+ BrownPLT.JavaScript.Lexer: natural :: CharParser st Integer
+ BrownPLT.JavaScript.Lexer: naturalOrFloat :: CharParser st (Either Integer Double)
+ BrownPLT.JavaScript.Lexer: octal :: CharParser st Integer
+ BrownPLT.JavaScript.Lexer: operator :: CharParser st String
+ BrownPLT.JavaScript.Lexer: parens :: CharParser st a -> CharParser st a
+ BrownPLT.JavaScript.Lexer: reserved :: String -> CharParser st ()
+ BrownPLT.JavaScript.Lexer: reservedOp :: String -> CharParser st ()
+ BrownPLT.JavaScript.Lexer: semi :: CharParser st String
+ BrownPLT.JavaScript.Lexer: squares :: CharParser st a -> CharParser st a
+ BrownPLT.JavaScript.Lexer: stringLiteral :: CharParser st String
+ BrownPLT.JavaScript.Lexer: symbol :: String -> CharParser st String
+ BrownPLT.JavaScript.Lexer: whiteSpace :: CharParser st ()
+ BrownPLT.JavaScript.Parser: emptyParsedJavaScript :: JavaScript a
+ BrownPLT.JavaScript.Parser: parseAssignExpr :: ExpressionParser st
+ BrownPLT.JavaScript.Parser: parseBlockStmt :: StatementParser st
+ BrownPLT.JavaScript.Parser: parseExpression :: ExpressionParser st
+ BrownPLT.JavaScript.Parser: parseJavaScriptFromFile :: (MonadIO m) => String -> m [Statement SourcePos]
+ BrownPLT.JavaScript.Parser: parseScript :: CharParser state (JavaScript SourcePos)
+ BrownPLT.JavaScript.Parser: parseScriptFromString :: String -> String -> Either ParseError (JavaScript SourcePos)
+ BrownPLT.JavaScript.Parser: parseSimpleExpr' :: GenParser Char st2 (Expression SourcePos)
+ BrownPLT.JavaScript.Parser: parseStatement :: StatementParser st
+ BrownPLT.JavaScript.Parser: parseString :: String -> [Statement SourcePos]
+ BrownPLT.JavaScript.Parser: type ExpressionParser state = CharParser state ParsedExpression
+ BrownPLT.JavaScript.Parser: type ParsedExpression = Expression SourcePos
+ BrownPLT.JavaScript.Parser: type ParsedStatement = Statement SourcePos
+ BrownPLT.JavaScript.Parser: type StatementParser state = CharParser state ParsedStatement
+ BrownPLT.JavaScript.PrettyPrint: expr :: Expression a -> Doc
+ BrownPLT.JavaScript.PrettyPrint: javaScript :: JavaScript a -> Doc
+ BrownPLT.JavaScript.PrettyPrint: renderExpression :: Expression a -> String
+ BrownPLT.JavaScript.PrettyPrint: renderStatements :: [Statement a] -> String
+ BrownPLT.JavaScript.PrettyPrint: stmt :: Statement a -> Doc
+ BrownPLT.JavaScript.Syntax: ArrayLit :: a -> [Expression a] -> Expression a
+ BrownPLT.JavaScript.Syntax: AssignExpr :: a -> AssignOp -> (Expression a) -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: BlockStmt :: a -> [Statement a] -> Statement a
+ BrownPLT.JavaScript.Syntax: BoolLit :: a -> Bool -> Expression a
+ BrownPLT.JavaScript.Syntax: BracketRef :: a -> (Expression a) -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: BreakStmt :: a -> (Maybe (Id a)) -> Statement a
+ BrownPLT.JavaScript.Syntax: CallExpr :: a -> (Expression a) -> [Expression a] -> Expression a
+ BrownPLT.JavaScript.Syntax: CaseClause :: a -> (Expression a) -> [Statement a] -> CaseClause a
+ BrownPLT.JavaScript.Syntax: CaseDefault :: a -> [Statement a] -> CaseClause a
+ BrownPLT.JavaScript.Syntax: CatchClause :: a -> (Id a) -> (Statement a) -> CatchClause a
+ BrownPLT.JavaScript.Syntax: CondExpr :: a -> (Expression a) -> (Expression a) -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: ContinueStmt :: a -> (Maybe (Id a)) -> Statement a
+ BrownPLT.JavaScript.Syntax: DoWhileStmt :: a -> (Statement a) -> (Expression a) -> Statement a
+ BrownPLT.JavaScript.Syntax: DotRef :: a -> (Expression a) -> (Id a) -> Expression a
+ BrownPLT.JavaScript.Syntax: EmptyStmt :: a -> Statement a
+ BrownPLT.JavaScript.Syntax: ExprInit :: (Expression a) -> ForInit a
+ BrownPLT.JavaScript.Syntax: ExprStmt :: a -> (Expression a) -> Statement a
+ BrownPLT.JavaScript.Syntax: ForInNoVar :: (Id a) -> ForInInit a
+ BrownPLT.JavaScript.Syntax: ForInStmt :: a -> (ForInInit a) -> (Expression a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: ForInVar :: (Id a) -> ForInInit a
+ BrownPLT.JavaScript.Syntax: ForStmt :: a -> (ForInit a) -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: FuncExpr :: a -> [(Id a)] -> (Statement a) -> Expression a
+ BrownPLT.JavaScript.Syntax: FunctionStmt :: a -> (Id a) -> [(Id a)] -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: Id :: a -> String -> Id a
+ BrownPLT.JavaScript.Syntax: IfSingleStmt :: a -> (Expression a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: IfStmt :: a -> (Expression a) -> (Statement a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: InfixExpr :: a -> InfixOp -> (Expression a) -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: IntLit :: a -> Int -> Expression a
+ BrownPLT.JavaScript.Syntax: LabelledStmt :: a -> (Id a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: ListExpr :: a -> [Expression a] -> Expression a
+ BrownPLT.JavaScript.Syntax: NewExpr :: a -> (Expression a) -> [Expression a] -> Expression a
+ BrownPLT.JavaScript.Syntax: NoInit :: ForInit a
+ BrownPLT.JavaScript.Syntax: NullLit :: a -> Expression a
+ BrownPLT.JavaScript.Syntax: NumLit :: a -> Double -> Expression a
+ BrownPLT.JavaScript.Syntax: ObjectLit :: a -> [(Prop a, Expression a)] -> Expression a
+ BrownPLT.JavaScript.Syntax: OpAdd :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpAssign :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignAdd :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignBAnd :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignBOr :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignBXor :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignDiv :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignLShift :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignMod :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignMul :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignSpRShift :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignSub :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpAssignZfRShift :: AssignOp
+ BrownPLT.JavaScript.Syntax: OpBAnd :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpBOr :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpBXor :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpDiv :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpGEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpGT :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpIn :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpInstanceof :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpLAnd :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpLEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpLOr :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpLShift :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpLT :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpMod :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpMul :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpNEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpSpRShift :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpStrictEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpStrictNEq :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpSub :: InfixOp
+ BrownPLT.JavaScript.Syntax: OpZfRShift :: InfixOp
+ BrownPLT.JavaScript.Syntax: ParenExpr :: a -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: PostfixDec :: PostfixOp
+ BrownPLT.JavaScript.Syntax: PostfixExpr :: a -> PostfixOp -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: PostfixInc :: PostfixOp
+ BrownPLT.JavaScript.Syntax: PrefixBNot :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixDec :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixDelete :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixExpr :: a -> PrefixOp -> (Expression a) -> Expression a
+ BrownPLT.JavaScript.Syntax: PrefixInc :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixLNot :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixMinus :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixPlus :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixTypeof :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PrefixVoid :: PrefixOp
+ BrownPLT.JavaScript.Syntax: PropId :: a -> (Id a) -> Prop a
+ BrownPLT.JavaScript.Syntax: PropNum :: a -> Integer -> Prop a
+ BrownPLT.JavaScript.Syntax: PropString :: a -> String -> Prop a
+ BrownPLT.JavaScript.Syntax: RegexpLit :: a -> String -> Bool -> Bool -> Expression a
+ BrownPLT.JavaScript.Syntax: ReturnStmt :: a -> (Maybe (Expression a)) -> Statement a
+ BrownPLT.JavaScript.Syntax: Script :: a -> [Statement a] -> JavaScript a
+ BrownPLT.JavaScript.Syntax: StringLit :: a -> String -> Expression a
+ BrownPLT.JavaScript.Syntax: SwitchStmt :: a -> (Expression a) -> [CaseClause a] -> Statement a
+ BrownPLT.JavaScript.Syntax: ThisRef :: a -> Expression a
+ BrownPLT.JavaScript.Syntax: ThrowStmt :: a -> (Expression a) -> Statement a
+ BrownPLT.JavaScript.Syntax: TryStmt :: a -> (Statement a) -> [CatchClause a] -> (Maybe (Statement a)) -> Statement a
+ BrownPLT.JavaScript.Syntax: VarDecl :: a -> (Id a) -> (Maybe (Expression a)) -> VarDecl a
+ BrownPLT.JavaScript.Syntax: VarDeclStmt :: a -> [VarDecl a] -> Statement a
+ BrownPLT.JavaScript.Syntax: VarInit :: [VarDecl a] -> ForInit a
+ BrownPLT.JavaScript.Syntax: VarRef :: a -> (Id a) -> Expression a
+ BrownPLT.JavaScript.Syntax: WhileStmt :: a -> (Expression a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: WithStmt :: a -> (Expression a) -> (Statement a) -> Statement a
+ BrownPLT.JavaScript.Syntax: data AssignOp
+ BrownPLT.JavaScript.Syntax: data CaseClause a
+ BrownPLT.JavaScript.Syntax: data CatchClause a
+ BrownPLT.JavaScript.Syntax: data Expression a
+ BrownPLT.JavaScript.Syntax: data ForInInit a
+ BrownPLT.JavaScript.Syntax: data ForInit a
+ BrownPLT.JavaScript.Syntax: data Id a
+ BrownPLT.JavaScript.Syntax: data InfixOp
+ BrownPLT.JavaScript.Syntax: data JavaScript a
+ BrownPLT.JavaScript.Syntax: data PostfixOp
+ BrownPLT.JavaScript.Syntax: data PrefixOp
+ BrownPLT.JavaScript.Syntax: data Prop a
+ BrownPLT.JavaScript.Syntax: data Statement a
+ BrownPLT.JavaScript.Syntax: data VarDecl a
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (CaseClause a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (CatchClause a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (Expression a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (ForInInit a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (ForInit a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (Id a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (JavaScript a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (Prop a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (Statement a)
+ BrownPLT.JavaScript.Syntax: instance (Data a) => Data (VarDecl a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (CaseClause a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (CatchClause a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (Expression a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (ForInInit a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (ForInit a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (Id a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (JavaScript a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (Prop a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (Statement a)
+ BrownPLT.JavaScript.Syntax: instance (Eq a) => Eq (VarDecl a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (CaseClause a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (CatchClause a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (Expression a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (ForInInit a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (ForInit a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (Id a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (JavaScript a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (Prop a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (Statement a)
+ BrownPLT.JavaScript.Syntax: instance (Ord a) => Ord (VarDecl a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (CaseClause a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (CatchClause a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (Expression a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (ForInInit a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (ForInit a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (Id a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (JavaScript a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (Prop a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (Statement a)
+ BrownPLT.JavaScript.Syntax: instance (Show a) => Show (VarDecl a)
+ BrownPLT.JavaScript.Syntax: instance Data AssignOp
+ BrownPLT.JavaScript.Syntax: instance Data InfixOp
+ BrownPLT.JavaScript.Syntax: instance Data PostfixOp
+ BrownPLT.JavaScript.Syntax: instance Data PrefixOp
+ BrownPLT.JavaScript.Syntax: instance Enum InfixOp
+ BrownPLT.JavaScript.Syntax: instance Eq AssignOp
+ BrownPLT.JavaScript.Syntax: instance Eq InfixOp
+ BrownPLT.JavaScript.Syntax: instance Eq PostfixOp
+ BrownPLT.JavaScript.Syntax: instance Eq PrefixOp
+ BrownPLT.JavaScript.Syntax: instance Ord AssignOp
+ BrownPLT.JavaScript.Syntax: instance Ord InfixOp
+ BrownPLT.JavaScript.Syntax: instance Ord PostfixOp
+ BrownPLT.JavaScript.Syntax: instance Ord PrefixOp
+ BrownPLT.JavaScript.Syntax: instance Show AssignOp
+ BrownPLT.JavaScript.Syntax: instance Show InfixOp
+ BrownPLT.JavaScript.Syntax: instance Show PostfixOp
+ BrownPLT.JavaScript.Syntax: instance Show PrefixOp
+ BrownPLT.JavaScript.Syntax: instance Typeable AssignOp
+ BrownPLT.JavaScript.Syntax: instance Typeable InfixOp
+ BrownPLT.JavaScript.Syntax: instance Typeable PostfixOp
+ BrownPLT.JavaScript.Syntax: instance Typeable PrefixOp
+ BrownPLT.JavaScript.Syntax: instance Typeable1 CaseClause
+ BrownPLT.JavaScript.Syntax: instance Typeable1 CatchClause
+ BrownPLT.JavaScript.Syntax: instance Typeable1 Expression
+ BrownPLT.JavaScript.Syntax: instance Typeable1 ForInInit
+ BrownPLT.JavaScript.Syntax: instance Typeable1 ForInit
+ BrownPLT.JavaScript.Syntax: instance Typeable1 Id
+ BrownPLT.JavaScript.Syntax: instance Typeable1 JavaScript
+ BrownPLT.JavaScript.Syntax: instance Typeable1 Prop
+ BrownPLT.JavaScript.Syntax: instance Typeable1 Statement
+ BrownPLT.JavaScript.Syntax: instance Typeable1 VarDecl
+ BrownPLT.JavaScript.Syntax: unId :: Id a -> String
Files
- Setup.hs +37/−0
- Setup.lhs +0/−29
- WebBits.cabal +23/−19
- src/BrownPLT/Html.hs +14/−0
- src/BrownPLT/Html/Instances.hs +66/−0
- src/BrownPLT/Html/PermissiveParser.hs +492/−0
- src/BrownPLT/Html/PrettyPrint.hs +53/−0
- src/BrownPLT/Html/RawScript.hs +35/−0
- src/BrownPLT/Html/Syntax.hs +86/−0
- src/BrownPLT/JavaScript.hs +17/−0
- src/BrownPLT/JavaScript/Crawl.hs +102/−0
- src/BrownPLT/JavaScript/Environment.hs +146/−0
- src/BrownPLT/JavaScript/HtmlEmbedding.hs +25/−0
- src/BrownPLT/JavaScript/Instances.hs +294/−0
- src/BrownPLT/JavaScript/Lexer.hs +64/−0
- src/BrownPLT/JavaScript/Parser.hs +668/−0
- src/BrownPLT/JavaScript/PrettyPrint.hs +239/−0
- src/BrownPLT/JavaScript/Syntax.hs +121/−0
- src/WebBits/Common.hs +0/−63
- src/WebBits/Data/Zipper.hs +0/−274
- src/WebBits/Html/Html.hs +0/−14
- src/WebBits/Html/Instances.hs +0/−66
- src/WebBits/Html/PermissiveParser.hs +0/−492
- src/WebBits/Html/PrettyPrint.hs +0/−54
- src/WebBits/Html/RawScript.hs +0/−34
- src/WebBits/Html/Syntax.hs +0/−84
- src/WebBits/JavaScript.hs +0/−21
- src/WebBits/JavaScript/Combinators.hs +0/−39
- src/WebBits/JavaScript/Crawl.hs +0/−80
- src/WebBits/JavaScript/Environment.hs +0/−304
- src/WebBits/JavaScript/HtmlEmbedding.hs +0/−26
- src/WebBits/JavaScript/Instances.hs +0/−291
- src/WebBits/JavaScript/JavaScript.hs +0/−19
- src/WebBits/JavaScript/Lexer.hs +0/−64
- src/WebBits/JavaScript/Parser.hs +0/−657
- src/WebBits/JavaScript/PrettyPrint.hs +0/−261
- src/WebBits/JavaScript/Syntax.hs +0/−117
+ Setup.hs view
@@ -0,0 +1,37 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+import qualified Data.List as L+import System.Directory+import qualified Data.Char as Ch+import System.Process (runCommand,waitForProcess)++isHaskellFile file = ".lhs" `L.isSuffixOf` file || ".hs" `L.isSuffixOf` file++moduleName file = L.takeWhile (/= '.') file++isRequested :: [String] -> String -> Bool+isRequested requestedTests test = + (map Ch.toLower test) `elem` (map (map Ch.toLower) requestedTests)++testMain args _ _ _ = do+ files <- getDirectoryContents "tests"+ let testFiles = filter isHaskellFile files+ let testModules = if null args+ then map moduleName testFiles+ else filter (isRequested args) (map moduleName testFiles)+ let testFuncs = map (++ ".main") testModules+ let testExpr = "sequence [ " ++ concat (L.intersperse "," testFuncs) ++ + " ] >>= \\cases -> runTestTT (TestList cases)"+ let moduleLine = concat (L.intersperse " " testModules)+ let cmd = "cd tests && ghc -XNoMonomorphismRestriction -fglasgow-exts " +++ "-package HUnit -package parsec-2.1.0.1 -i:../src -e \"" ++ + testExpr ++ " >> return ()\" " ++ moduleLine+ putStrLn "Testing command is:"+ putStrLn cmd+ putStrLn "\nLoading tests..."+ handle <- runCommand cmd+ waitForProcess handle+ putStrLn "Testing complete. Errors reported above (if any)."+++main = defaultMainWithHooks (simpleUserHooks { runTests = testMain })
− Setup.lhs
@@ -1,29 +0,0 @@-#!/usr/bin/env runhaskell-> import Distribution.Simple-> import qualified Data.List as L-> import System.Directory-> import System.Process (runCommand,waitForProcess)--> isHaskellFile file = ".lhs" `L.isSuffixOf` file || ".hs" `L.isSuffixOf` file--> moduleName file = L.takeWhile (/= '.') file--> testMain _ _ _ _ = do-> files <- getDirectoryContents "tests"-> let testModules = [moduleName f | f <- files, isHaskellFile f]-> let testFuncs = map (++ ".main") testModules-> let testExpr = "sequence [ " ++ concat (L.intersperse "," testFuncs) ++ -> " ] >>= \\cases -> runTestTT (TestList cases)"-> let moduleLine = concat (L.intersperse " " testModules)-> let cmd = "cd tests && ghc -XNoMonomorphismRestriction -fglasgow-exts " ++-> "-package HUnit -i:../src -e \"" ++ testExpr ++ -> " >> return ()\" " ++ moduleLine-> putStrLn "Testing command is:"-> putStrLn cmd-> putStrLn "\nLoading tests..."-> handle <- runCommand cmd-> waitForProcess handle-> putStrLn "Testing complete. Errors reported above (if any)."- --> main = defaultMainWithHooks (simpleUserHooks { runTests = testMain })
WebBits.cabal view
@@ -1,7 +1,7 @@ Name: WebBits-Version: 0.11.0+Version: 0.14.0 Cabal-Version: >= 1.2.3-Copyright: Copyright (c) 2007-2008 Arjun Guha and Spiridon Eliopoulos+Copyright: Copyright (c) 2007-2009 Arjun Guha and Spiridon Eliopoulos License: LGPL License-file: LICENSE Author: Arjun Guha, Spiridon Eliopoulos@@ -16,16 +16,16 @@ WebBits is a collection of libraries for working with JavaScript embeded in HTML files. Highlights include: .- * @WebBits.JavaScript.Crawl@ returns all JavaScript in an HTML page, including+ * @BrownPLT.JavaScript.Crawl@ returns all JavaScript in an HTML page, including JavaScript from imported script files (@\<script src=...\>@). .- * @WebBits.JavaScript.Environment@ annotates JavaScript syntax with its static- environment and returns a list of free identifiers.+ * @BrownPLT.JavaScript.Environment@ annotates JavaScript syntax with its + static environment and returns a list of free identifiers. .- * @WebBits.JavaScript.Parser@ is a JavaScript parser that is largely based on+ * @BrownPLT.JavaScript.Parser@ is a JavaScript parser that is largely based on JavaScript 1.5. .- * @WebBits.Html.Parser@ is a permissive HTML parser.+ * @BrownPLT.Html.Parser@ is a permissive HTML parser. Library Hs-Source-Dirs:@@ -35,16 +35,20 @@ ghc-options: -fwarn-incomplete-patterns Extensions: - Generics Rank2Types MultiParamTypeClasses FunctionalDependencies- TypeSynonymInstances FlexibleInstances FlexibleContexts- DeriveDataTypeable NoMonomorphismRestriction RelaxedPolyRec+ Generics TypeSynonymInstances DeriveDataTypeable Exposed-Modules:- WebBits.Data.Zipper- WebBits.Html.Html WebBits.Html.Syntax WebBits.Html.PermissiveParser- WebBits.Html.PrettyPrint WebBits.Html.Instances WebBits.Common- WebBits.Html.RawScript WebBits.JavaScript.Combinators- WebBits.JavaScript.HtmlEmbedding WebBits.JavaScript.Instances- WebBits.JavaScript.JavaScript WebBits.JavaScript.Lexer - WebBits.JavaScript.Parser WebBits.JavaScript.PrettyPrint- WebBits.JavaScript.Syntax WebBits.JavaScript.Environment- WebBits.JavaScript.Crawl WebBits.JavaScript+ BrownPLT.Html+ BrownPLT.Html.Syntax+ BrownPLT.Html.PermissiveParser+ BrownPLT.Html.PrettyPrint + BrownPLT.Html.Instances+ BrownPLT.Html.RawScript+ BrownPLT.JavaScript + BrownPLT.JavaScript.HtmlEmbedding + BrownPLT.JavaScript.Instances+ BrownPLT.JavaScript.Lexer + BrownPLT.JavaScript.Parser+ BrownPLT.JavaScript.PrettyPrint+ BrownPLT.JavaScript.Syntax + BrownPLT.JavaScript.Crawl+ BrownPLT.JavaScript.Environment
+ src/BrownPLT/Html.hs view
@@ -0,0 +1,14 @@+-- |Rexports various modules of the HTML library. It's best to use this in lieu+-- of selectively importing the following libraries.+module BrownPLT.Html+ ( module BrownPLT.Html.Syntax+ -- PermissiveParser+ , renderHtml+ , parseHtmlFromFile+ , parseHtmlFromString+ ) where+ +import BrownPLT.Html.Syntax+import BrownPLT.Html.PermissiveParser+import BrownPLT.Html.PrettyPrint -- no names, only instances+import BrownPLT.Html.Instances -- no names, only instances
+ src/BrownPLT/Html/Instances.hs view
@@ -0,0 +1,66 @@+module BrownPLT.Html.Instances() where++import qualified Prelude as Prelude+import Prelude (Functor,map,fmap)+import qualified Data.List as List+import qualified Data.Char as Char+import Data.Foldable+import Data.Traversable+import Control.Applicative++import BrownPLT.Html.Syntax++ltraverse:: (Traversable t, Applicative f) => (a -> f b) -> [t a] -> f [t b]+ltraverse f [] = pure []+ltraverse f (x:xs) = pure (:) <*> (traverse f x) <*> ltraverse f xs++instance Functor (Attribute a) where+ fmap f (Attribute id val a) = Attribute id val a+ fmap f (AttributeExpr a id script def) = AttributeExpr a id (f script) def++instance Functor (Html a) where+ fmap f (Element id attrs children a) = + Element id (map (fmap f) attrs) (map (fmap f) children) a+ fmap f (Text str a) = Text str a+ fmap f (Comment str a) = Comment str a+ fmap f (HtmlSeq xs) = HtmlSeq (map (fmap f) xs)+ fmap f (ProcessingInstruction str a) = ProcessingInstruction str a+ fmap f (InlineScript script a def) = InlineScript (f script) a def+ fmap f (Script script a) = Script (f script) a++instance Foldable (Attribute a) where+ foldr f x (Attribute id val a) = x+ foldr f x (AttributeExpr a id script def) = f script x++instance Foldable (Html a) where+ foldr f x (Element id attrs children a) =+ Prelude.foldr (\child x' -> foldr f x' child) x children + foldr f x (Text str a) = x+ foldr f x (Comment str a) = x+ foldr f x (HtmlSeq ys) = + Prelude.foldr (\child x' -> foldr f x' child) x ys+ foldr f x (ProcessingInstruction str a) = x+ foldr f x (InlineScript script a def) = f script x+ foldr f x (Script script a) = f script x++instance Traversable (Attribute a) where+ traverse f (Attribute id val a) =+ pure (Attribute id val a)+ traverse f (AttributeExpr a id script def) =+ (AttributeExpr a id) <$> (f script) <*> pure def++instance Traversable (Html a) where+ traverse f (Element id attrs children a) = + (Element id) <$> ltraverse f attrs <*> ltraverse f children <*> pure a+ traverse f (Text str a) = + pure (Text str a)+ traverse f (Comment str a) = + pure (Comment str a)+ traverse f (HtmlSeq xs) = + HtmlSeq <$> ltraverse f xs+ traverse f (ProcessingInstruction str a) = + pure (ProcessingInstruction str a)+ traverse f (InlineScript script a def) =+ InlineScript <$> (f script) <*> pure a <*> pure def+ traverse f (Script script a) = + Script <$> (f script) <*> pure a
+ src/BrownPLT/Html/PermissiveParser.hs view
@@ -0,0 +1,492 @@+-- |A structure-recovering parser for malformed documents.+--+-- Copyright 2007-2008 Arjun Guha.+-- Based on HtmlPrag 0.16 Copyright (C) 2003 - 2005 Neil W. Van Dyke. +--+-- This program is Free Software; you can redistribute it and/or modify it under+-- the terms of the GNU Lesser General Public License as published by the Free+-- Software Foundation; either version 2.1 of the License, or (at your option)+-- any later version. This program is distributed in the hope that it will be+-- useful, but without any warranty; without even the implied warranty of+-- merchantability or fitness for a particular purpose. See +-- <http://www.gnu.org/copyleft/lesser.html> for details. For other license+-- options and consulting, contact the author.+module BrownPLT.Html.PermissiveParser+ ( html+ , parseHtmlFromFile+ , parseHtmlFromString+ -- tokenizer is exported primarily for testing+ , tokens+ , Token+ ) where++import Control.Monad+import Text.ParserCombinators.Parsec hiding (token,tokens)+import qualified Text.ParserCombinators.Parsec as Parsec+import Data.Char (toLower)+import Data.List (intersperse)++import qualified BrownPLT.Html.Syntax as Html+import BrownPLT.Html.Syntax (HtmlId,Attribute,Script(..))++type ParsedHtml s = Html.Html SourcePos s+type ParsedAttribute s = Html.Attribute SourcePos s++--------------------------------------------------------------------------------+-- Parsers generate warnings++data Warning = StringWarning SourcePos String++instance Show Warning where+ show (StringWarning p s) = "Warning parsing HTML: " ++ s+ showList [] s = s+ showList (x:xs) s = show x ++ ('\n':showList xs s)++warn:: String -> GenParser tok [Warning] ()+warn s = do+ p <- getPosition+ updateState ((StringWarning p s):)++noWarnings:: [Warning]+noWarnings = []+ ++-- A structure-recovering parser for malformed documents, derived from+-- Neil W. Van Dyke's htmlprag library for PLT Scheme++-- The elements in the list can legally enclose the 1st element of the pair.+parentConstraints:: [(HtmlId,[HtmlId])]+parentConstraints =+ [("area",["map"]),+ ("body",["html"]),+ ("caption", ["table"]),+ ("colgroup", ["table"]),+ ("dd", ["dl"]),+ ("dt", ["dl"]),+ ("frame", ["frameset"]),+ ("head", ["html"]),+ ("isindex", ["head"]),+ ("li", ["dir", "menu", "ol", "ul"]),+ ("meta", ["head"]),+ ("noframes", ["frameset"]),+ ("option", ["select"]),+ ("p", ["body", "td", "th"]),+ ("param", ["applet"]),+ ("tbody", ["table"]),+ ("td", ["tr"]),+ ("th", ["tr"]),+ ("thead", ["table"]),+ ("title", ["head"]),+ ("tr", ["table", "tbody", "thead"])]++-- |List of HTML elements that are empty.+emptyElements:: [HtmlId]+emptyElements = + ["area", "base", "br", "frame", "hr", "img", "input", "isindex", "keygen", + "link", "meta", "object", "param", "spacer", "wbr"]++isLegalChildOf:: HtmlId -> HtmlId -> Bool+isLegalChildOf child parent =+ case lookup child parentConstraints of+ Nothing -> True+ (Just legalParents) -> parent `elem` legalParents+ +isEmptyElement:: HtmlId -> Bool+isEmptyElement element = element `elem` emptyElements++--}}}++--------------------------------------------------------------------------------+-- Parses an HTML file into a stream of tokens.++-- The auxillary parsing functions return values of this type.+data Script s => Token s+ = Text SourcePos String+ | EntityToken SourcePos String+ | EntityInt SourcePos Int+ | Tag SourcePos HtmlId [Attribute SourcePos s] Bool {-closed?-}+ | Script SourcePos s+ | Inline SourcePos s String+ | EndTag SourcePos HtmlId+ | Comment SourcePos String+ | DoctypeToken SourcePos String String String (Maybe String)+++token:: Script s => Bool -> [Attribute SourcePos s] + -> CharParser [Warning] (Token s)+token expectedScript prevAttrs = case expectedScript of+ True -> (liftM2 Script getPosition (parseScriptBlock prevAttrs)) + <?> "expected a script after a <script> tag"+ False -> doctype <|> comment <|> tag <|> endTag <|> inlineScript <|> entity + <|> text++tokens:: Script s => CharParser [Warning] [Token s]+tokens = (eof >> return []) <|> tokens' where+ tokens' = do + t <- token False []+ case t of+ (Tag _ "script" attrs False) -> do s <- token True attrs+ ts <- tokens+ return (t:s:ts)+ _ -> tokens >>= return.(t:)++--------------------------------------------------------------------------------+-- Parsers for various components of HTML++qname:: CharParser st String+qname = do+ x <- letter+ xs <- many (noneOf "/*=<>\"\' \v\f\t\r\n")+ return (x:xs)++-- |We do not permit spaces between the hyphens and the right-angle in the+-- terminating '-->'.+comment:: Script s => CharParser st (Token s) +comment =+ let notDoubleHyphen = try (char '-' >> notFollowedBy (char '-') >> return '-')+ notHyphen = noneOf "-"+ in do try (string "<!--")+ pos <- getPosition+ msg <- many (notHyphen <|> notDoubleHyphen)+ string "-->"+ return (Comment pos msg)++endTag:: Script s => CharParser [Warning] (Token s)+endTag = do+ pos <- getPosition+ string "</"+ name <- qname <?> "closing tag\'s name"+ junk <- manyTill anyChar (char '>') -- permits junk between tag name and '>'+ unless (null junk) (warn $ "extra characters: " ++ junk ++ + "; assuming tag name is " ++ name)+ return (EndTag pos name)+ +doctype:: Script s => CharParser [Warning] (Token s)+doctype = do+ p <- getPosition+ try (string "<!DOCTYPE")+ spaces+ top <- qname <?> "top-element name"+ spaces+ avail <- qname <?> "availability"+ spaces+ regEtc <- quotedString <?> "registration, etc."+ spaces+ uri <- optionMaybe quotedString+ spaces+ string ">"+ return (DoctypeToken p top avail regEtc uri)+ +entity:: Script s => CharParser [Warning] (Token s)+entity = do+ char '&'+ pos <- getPosition+ name <- many alphaNum <|> (char '#' >> many1 digit)+ when (null name) (warn "no identifer or number after &")+ (char ';' >> return ()) <|> (warn "expected semi-colon after entity") + return (EntityToken pos name)+ +notScript:: CharParser a Char+notScript = try (char '{' >> notFollowedBy (char '!') >> return '{')++-- Parses raw text, upto an opening angle-bracket ('<').+text:: Script s => CharParser st (Token s)+text = do+ pos <- getPosition+ cs <- many1 (noneOf "<{" <|> notScript) -- Doesn't consume the terminating angle bracket.+ return (Text pos cs)++-- Strings that are either double-quoted or single-quoted. Note that HTML+-- strings contain no escape sequences.+quotedString:: CharParser a String+quotedString =+ (char '"' >> manyTill anyChar (char '"')) <|>+ (char '\'' >> manyTill anyChar (char '\'')) <?>+ "quoted string (double-quotes or single quotes)"++-- Parses text to the right of a triple-stick in an inline expression. We have+-- to ensure that if we read a `!,' it isn't immediately followed by `}.'+initText =+ let notEnd = try (char '!' >> notFollowedBy (char '}') >> return '!')+ in many1 (notEnd <|> noneOf "!")++scriptValue:: Script s => CharParser a (s,String)+scriptValue =+ case parseAttributeScript of+ Nothing -> fail "attribute-script parser not defined"+ (Just parser) -> do string "{!"+ script <- parser+ init <- (string "!}" >> return "") <|> + (string "|||" >> initText >>= + (\s -> string "!}" >> return s))+ return (script,init)++number:: CharParser a String+number = many1 digit++-- +nonquotedAttribute:: CharParser [Warning] String+nonquotedAttribute = do+ x <- alphaNum <|> oneOf "_"+ xs <- many (noneOf "/*=<>\"\' \v\f\t\r\n")+ warn $ "non-quoted attribute value: " ++ (x:xs)+ return (x:xs)+++attribute:: Script s => CharParser [Warning] (Html.Attribute SourcePos s)+attribute = do+ pos <- getPosition+ name <- qname <?> "attribute name"+ spaces+ value <- (do char '='+ spaces+ (liftM Right scriptValue)+ <|> (liftM Left (quotedString <|> nonquotedAttribute)) + <?> "attribute value")+ <|> (return $ Left "") -- Unspecified values are empty values.+ case value of+ (Left v) -> return $ Html.Attribute name v pos+ (Right (s,d)) -> return $ Html.AttributeExpr pos name s d++-- Takes the name of the immediately-enclosing parent tag as an argument.+tag:: Script s => CharParser [Warning] (Token s)+tag = do+ try (char '<' >> notFollowedBy (char '/'))+ pos <- getPosition+ name <- qname <?> "opening tag\'s name"+ spaces+ attributes <- (attribute `sepEndBy` spaces)+ (char '>' >> return (Tag pos name attributes False))+ <|> (string "/>" >> return (Tag pos name attributes True))+ <?> "end of tag (i.e. \">\")"+++-- Parses an inline (curly-banged) script, if an inline-script parser has been+-- specified (i.e. not Nothing). Two-character lookahead for the ``{!,'' after+-- which control is passed to the inline script parser. Once control returns,+-- the parser expects to see the closing ``!}.''+inlineScript:: Script s => CharParser a (Token s)+inlineScript =+ case parseInlineScript of+ Nothing -> fail "no inline script parser specified." -- TODO: appropriate?+ (Just parser) -> do string "{!" <?> "{! script !}"+ pos <- getPosition+ script <- parser+ spaces+ init <- (string "!}" >> return "") <|>+ (string "|||" >> initText >>= + (\s -> string "!}" >> return s))+ return $ Inline pos script init+++-- Parses a stream of tokens, with a script parser, s and returns values of +-- type a.+type TokenParser s a = GenParser (Token s) [Warning] a++instance Script s => Show (Token s) where+ show = tokenShow++tokenShow token = case token of+ (Text _ s) -> s+ (EntityToken _ s) -> "&" ++ s ++ ";"+ (EntityInt _ n) -> "&#" ++ show n ++ ";"+ (Tag _ id attrs closed) -> + "<" ++ id ++ " ... " ++ closing where+ closing = if closed then "/>" else ">"+ (Script _ s) -> "/* script body omitted */"+ (Inline _ s _)-> "{! /* script */ !}"+ (EndTag _ id) -> "</" ++ show id ++ ">"+ (Comment _ s) -> "<!-- " ++ show s ++ " -->"+ (DoctypeToken _ top avail desc Nothing) ->+ "<!DOCTYPE " ++ top ++ " " ++ avail ++ " " ++ show desc ++ ">"+ (DoctypeToken _ top avail desc (Just uri)) ->+ "<!DOCTYPE " ++ top ++ " " ++ avail ++ " " ++ show desc ++ " " + ++ show uri ++ ">" ++tokenPos tok = case tok of+ (Text p _) -> p+ (EntityToken p _) -> p+ (EntityInt p _) -> p+ (Tag p _ _ _) -> p+ (Script p _) -> p+ (Inline p _ _) -> p+ (EndTag p _) -> p+ (Comment p _) -> p+ (DoctypeToken p _ _ _ _) -> p+ +textToken :: Script s => TokenParser s (ParsedHtml s)+textToken = Parsec.token tokenShow tokenPos $ \t -> case t of+ Text _ s -> Just (Html.Text s (tokenPos t))+ otherwise -> Nothing+ +entityToken :: Script s => TokenParser s (ParsedHtml s)+entityToken =+ Parsec.token tokenShow tokenPos+ (\t -> case t of+ (EntityToken p s) -> Just (Html.Text ("&" ++ s ++ ";") p)+ (EntityInt p n) -> Just (Html.Text ("&#" ++ show n ++ ";") p)+ otherwise -> Nothing)+ +commentToken :: Script s => TokenParser s (ParsedHtml s)+commentToken = + Parsec.token tokenShow tokenPos+ (\t -> case t of+ (Comment _ s) -> Just (Html.Comment s (tokenPos t))+ otherwise -> Nothing)++scriptToken :: Script s => TokenParser s (ParsedHtml s) +scriptToken = + Parsec.token tokenShow tokenPos+ (\t -> case t of+ (Script p s) -> Just (Html.Script s p)+ otherwise -> Nothing)++inlineToken :: Script s => TokenParser s (ParsedHtml s)+inlineToken = + Parsec.token tokenShow tokenPos+ (\t -> case t of+ (Inline p s d) -> Just (Html.InlineScript s p d)+ otherwise -> Nothing)+ +endToken :: Script s => TokenParser s HtmlId+endToken = + Parsec.token tokenShow tokenPos+ (\t -> case t of+ (EndTag p s) -> Just s+ otherwise -> Nothing)++tagToken :: Script s => TokenParser s (Token s)+tagToken = + Parsec.token tokenShow tokenPos+ (\t -> case t of+ (Tag p id attrs closed) -> Just t+ otherwise -> Nothing)++doctypeToken :: Script s => TokenParser s (Token s)+doctypeToken = Parsec.token tokenShow tokenPos $ \t -> case t of+ DoctypeToken _ _ _ _ _ -> Just t+ otherwise -> Nothing++--------------------------------------------------------------------------------+-- HTML fragments++-- |An HTML fragment represents an HTML element with a sequence of children.+data HtmlFragment s = Fragment {+ fragmentPosition :: SourcePos,+ fragmentName :: HtmlId,+ fragmentAttributes :: [ParsedAttribute s],+ fragmentChildren :: [ParsedHtml s]+}++closeFragment:: HtmlFragment s -> ParsedHtml s+closeFragment (Fragment p htmlId attrs children) = + Html.Element htmlId attrs (reverse children) p++appendChildToFragment child fragment =+ fragment { fragmentChildren = child : (fragmentChildren fragment) }+ +atomic :: Script s => TokenParser s (ParsedHtml s)+atomic =+ textToken <|> commentToken <|> scriptToken <|> inlineToken <|> entityToken+++maybeClose :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s] +maybeClose es = do+ htmlId <- endToken+ let close [] = do + warn $ "unmatched closing tag \"" ++ htmlId ++ "\"; ignoring"+ return es+ close (e:e2:es) | fragmentName e == htmlId = do+ return $ (appendChildToFragment (closeFragment e) e2) : es+ close (e:e2:es) | otherwise = + let e2' = appendChildToFragment (closeFragment e) e2+ in close (e2':es)+ close [e] | fragmentName e == htmlId = do+ return [e]+ close [e] | otherwise = do+ warn $ "unmatched closing tag \"" ++ htmlId ++ "\"; ignoring"+ return [e]+ in close es++open :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s]+open [] = fail "PermissiveParser.open: invalid state (1)"+open (e:es) = do+ (Tag p id attrs isClosed) <- tagToken+ case isClosed of+ True -> return $ (appendChildToFragment (Html.Element id attrs [] p) e) : es+ False ->+ case isEmptyElement id of+ True -> do warn $ "empty-element, \"" ++ id + ++ "\" was not immediately closed"+ return $ (appendChildToFragment (Html.Element id attrs [] p)+ e) : es+ False -> do+ let fragment = Fragment p id attrs []+ -- If we reach the root, simply make 'fragment' a child.+ let insert [root] = [fragment,root]+ -- The <html> element is the only child of the root. This+ -- catches all other elements and makes them children of <html>.+ insert [html,root] = [fragment,html,root]+ insert (e1:e2:es) | id `isLegalChildOf` (fragmentName e1) =+ fragment:e1:e2:es+ insert (e1:e2:es) | otherwise =+ insert $ (appendChildToFragment (closeFragment e1) e2):es + insert [] = fail "PermissiveParser.open: invalid state (2)"+ return $ insert (e:es)++structured es = do+ maybeClose es <|> open es++html' :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s]+html' [] = fail "PermissiveParser.html': invalid state (1)"+html' (e:es) =+ (do a <- atomic+ html' $ (appendChildToFragment a e):es) <|>+ (structured (e:es) >>= html') <|>+ (return (e:es))++parseRoot = Fragment (error "parseRoot: position is meaningless") + "DOCROOT" (error "parseRoot: attributes are meaningless")+ []++html :: Script s => CharParser [Warning] (Html.Html SourcePos s)+html = do+ let parser = do+ -- optional doctypeToken -- ignored+ fragments <- html' [parseRoot]+ case fragments of+ [fragment] -> case closeFragment fragment of + Html.Element _ _ (c:_) _ -> do+ ws <- getState+ return (ws,head [c])+ otherwise -> fail "root element not found"+ otherwise -> fail "no root / multiple roots"+ toks <- tokens -- a stream of HTML entities+ pos <- Parsec.getPosition+ warnings <- Parsec.getState+ case Parsec.runParser parser warnings (Parsec.sourceName pos) toks of+ Left e -> fail $ "unparsable HTML: " ++ (show e)+ Right (ws,html) -> Parsec.setState ws >> return html ++htmlWithWarnings :: Script s + => CharParser [Warning] (Html.Html SourcePos s,[Warning])+htmlWithWarnings = do+ h <- html+ ws <- getState+ return (h,ws)++parseHtmlFromString :: Script s => String -> String -> Either Parsec.ParseError (Html.Html SourcePos s,[Warning])+parseHtmlFromString sourceName sourceText = + case Parsec.runParser htmlWithWarnings noWarnings sourceName sourceText of+ Left err -> Left err+ Right (html,ws) -> Right (html,ws) ++parseHtmlFromFile :: Script s + => String + -> IO (Either Parsec.ParseError + (Html.Html SourcePos s,[Warning]))+parseHtmlFromFile filename = do+ chars <- readFile filename+ case Parsec.runParser htmlWithWarnings noWarnings filename chars of+ Left err -> return (Left err)+ Right (html,ws) -> return $ Right (html,ws)
+ src/BrownPLT/Html/PrettyPrint.hs view
@@ -0,0 +1,53 @@+-- |Pretty-printer for HTML. This modules exports no names. It only defines+-- instances of 'PrettyPrintable' for HTML. +module BrownPLT.Html.PrettyPrint+ ( html+ , renderHtml+ ) where++import qualified Data.List as List+import qualified Data.Char as Char+import Text.PrettyPrint.HughesPJ++import BrownPLT.Html.Syntax++renderHtml :: Script s => Html a s -> String+renderHtml = render.html++vert [] = empty+vert [doc] = doc+vert (doc:docs) = doc <> text "<!--" $+$+ text "-->" <> vert docs++attr :: Script s => Attribute a s -> Doc+attr a = case a of+ Attribute name value _ ->+ text name <> equals <> doubleQuotes (text value)+ AttributeExpr _ n v "" ->+ text n <> equals <> text "{!" <+> prettyPrintScript v <+> text "!}"+ AttributeExpr _ n v d ->+ text n <> equals <> text "{!" <+> prettyPrintScript v <+> text "|||" <+> + text d <+> text "!}"++html :: Script s => Html a s -> Doc+html x = case x of+ -- The <script> tag must be terminated by </script>.+ -- <script lang= src= /> doesn't work.+ Element name attrs children _ ->+ -- WARNING: Spacing is very sensitive+ text "<" <> text name <+> hsep (map attr attrs) <> text ">" -- opening+ $$ (nest 2 (vcat (map html children))) -- body+ $$ text "</" <> text name <> text ">" -- closing+ -- Horizontally aligned material that is vertically represented in source.+ HtmlSeq xs -> vert (map html xs)+ Text str _ -> text (skipWs str) where+ skipWs str = List.dropWhile Char.isSpace str+ Comment str _ -> text "<!--" <+> text str <+> text "-->"+ ProcessingInstruction str _ -> text "<?" <> text str <> text ">"+ Script s _ -> prettyPrintScript s+ InlineScript script _ "" ->+ text "{!" <+> prettyPrintScript script <+> text "!}"+ InlineScript script _ init -> + text "{!" <+> prettyPrintScript script <+> text "|||" <+> + text init <+> text "!}"+
+ src/BrownPLT/Html/RawScript.hs view
@@ -0,0 +1,35 @@+module BrownPLT.Html.RawScript+ ( RawScript (..)+ , parseFromFile+ , parseFromString+ , RawHtml+ ) where++import Data.Generics (Data, Typeable)+import Text.PrettyPrint.HughesPJ (text)+import Text.ParserCombinators.Parsec+import BrownPLT.Html.Syntax+import BrownPLT.Html.PermissiveParser++type RawHtml = Html SourcePos RawScript+++data RawScript = RawScript String deriving (Show,Eq,Typeable,Data)+++instance Script RawScript where++ prettyPrintScript (RawScript s) = text s+ parseInlineScript = Nothing+ + parseAttributeScript = Nothing+ + parseScriptBlock _ = do+ s <- manyTill anyChar (string "</script>")+ return (RawScript s)+ ++parseFromString :: String -> RawHtml+parseFromString s = case parseHtmlFromString "" s of+ Left e -> error (show e)+ Right (html,_) -> html
+ src/BrownPLT/Html/Syntax.hs view
@@ -0,0 +1,86 @@+-- |Datatypes for HTML parameterized over an annotation type and a script type.+module BrownPLT.Html.Syntax + (+ -- * HTML Data Structures+ HtmlId,AttributeValue, Attribute (..), Html (..)+ -- * The Script class+ , Script (..)+ -- * Miscellaneous Functions+ , attributeValue, attributeUpdate, attributeSet, isAttributeExpr+ ) where++import Text.ParserCombinators.Parsec (CharParser, SourcePos)+import Text.PrettyPrint.HughesPJ (Doc)+import Data.Generics (Data, Typeable)++--------------------------------------------------------------------------------+-- Types++type HtmlId = String+type AttributeValue = String++data Attribute a s+ = Attribute HtmlId AttributeValue a+ | AttributeExpr a HtmlId s String+ deriving (Show,Eq,Typeable,Data)++data Html a sc+ = Element HtmlId [Attribute a sc] [Html a sc] a+ | Text String a+ | Comment String a+ | HtmlSeq [Html a sc] -- ^must be a non-empty list+ | ProcessingInstruction String a+ | InlineScript sc a String+ | Script sc a+ deriving (Show,Eq,Typeable,Data)+ +--------------------------------------------------------------------------------+-- The Script class++-- |A type 't' of the 'Script' class can be parsed using 'Parsec'. 't' is of+-- kind '* -> *', as the parsed AST should be annotated with souce locations+-- (see 'Text.ParserCombinators.Parsec.SourcePos').+--+-- The big deal here is that we can embed a parser for some scripting language,+-- (e.g. Javascript) into this HTML parser with ease, while preserving source+-- locations. The Html datatype is parameterized over a script parser (an+-- instance of Script).+class Script t where+ prettyPrintScript :: t -> Doc+ parseScriptBlock:: [Attribute SourcePos t] -> CharParser a t+ -- An inline script parser, which may be Nothing if the scripting language+ -- does not support inline scripts.+ parseInlineScript:: Maybe (CharParser a t)+ -- A parser for script-expressions defined inline as attribute values.+ parseAttributeScript:: Maybe (CharParser a t)+ +--------------------------------------------------------------------------------+-- HTML navigation++isAttributeExpr (AttributeExpr _ _ _ _) = True+isAttributeExpr _ = False++-- |Returns the value of the attribute in the list, or 'Nothing' if it doesn't+-- exist of the value is an inline-expression.+attributeValue:: HtmlId -> [Attribute a s] -> Maybe String+attributeValue name [] = Nothing+attributeValue name ((AttributeExpr pos name' expr init):rest) =+ if name == name' then Nothing+ else attributeValue name rest+attributeValue name ((Attribute name' value _):rest) =+ if name == name' then Just value+ else attributeValue name rest++attributeSet:: HtmlId -> String -> [Attribute a s] -> [Attribute a s]+attributeSet n v attrs = attributeUpdate n (\_ -> v) attrs++attributeUpdate:: HtmlId -> (String -> String) -> [Attribute a s] + -> [Attribute a s]+attributeUpdate n f [] = + [Attribute n (f "") (error "attributeUpdate--no value")] -- TODO: undefined?!+attributeUpdate n _ ((AttributeExpr _ _ _ _):_) =+ error $ "attributeUpdate: " ++ n ++ " is an expression-attribute."+attributeUpdate n f ((Attribute n' v p):attrs) =+ if n' == n then (Attribute n (f v) p):attrs+ else (Attribute n' v p):(attributeUpdate n f attrs)+
+ src/BrownPLT/JavaScript.hs view
@@ -0,0 +1,17 @@+-- |Re-exports commonly used modules.+module BrownPLT.JavaScript+ ( module BrownPLT.JavaScript.Syntax+ , module BrownPLT.JavaScript.HtmlEmbedding+ , module BrownPLT.JavaScript.Parser+ -- JavaScript.Instances exports nothing+ , renderStatements+ , renderExpression+ ) where+++import BrownPLT.JavaScript.Syntax+import BrownPLT.JavaScript.Parser+import BrownPLT.JavaScript.PrettyPrint+import BrownPLT.JavaScript.HtmlEmbedding++import BrownPLT.JavaScript.Instances
+ src/BrownPLT/JavaScript/Crawl.hs view
@@ -0,0 +1,102 @@+-- |Crawls an HTML page for JavaScript+module BrownPLT.JavaScript.Crawl + ( getPageJavaScript+ ) where++import Control.Monad+import Data.List+import Data.Char (toLower)+import Data.Generics+import System.IO+import Text.ParserCombinators.Parsec.Pos (SourcePos, sourceName)+import Text.ParserCombinators.Parsec(parse,setPosition,incSourceColumn,Column,sourceLine,sourceColumn)++import BrownPLT.Html.Syntax+import qualified BrownPLT.JavaScript as Js+++instance Typeable SourcePos where+ typeOf _ = + mkTyConApp (mkTyCon "Text.ParserCombinators.Parsec.Pos.SourcePos") []++ +-- Complete guesswork. It seems to work.+-- This definition is incomplete.+instance Data SourcePos where+ -- We treat source locations as opaque. After all, we don't have access to+ -- the constructor.+ gfoldl k z pos = z pos+ toConstr _ = sourcePosConstr1 where+ sourcePosConstr1 = mkConstr sourcePosDatatype "SourcePos" [] Prefix+ sourcePosDatatype = mkDataType "SourcePos" [sourcePosConstr1]+ gunfold = error "gunfold is not defined for SourcePos"+ dataTypeOf = error "dataTypeOf is not defined for SourcePos"+++-- |Returns the source of the script.+scriptSrc:: Js.ParsedJsHtml -> [String]+scriptSrc (Element tag attrs _ _) | (map toLower tag) == "script" =+ case attributeValue "src" attrs of -- TODO: Check for type="javascript"?+ Just "" -> []+ Just url -> [url]+ Nothing -> []+scriptSrc _ =+ []+++-- |Returns a list of URIs for external Javascript files referenced in the page.+importedScripts:: Js.ParsedJsHtml -> [String]+importedScripts = everything (++) (mkQ [] scriptSrc)++-- |Returns the top-level statements of a script.+scriptText :: Js.ParsedJsHtml -> [Js.ParsedStatement]+scriptText (Script (Js.Script _ stmts) _) = stmts+scriptText _ = []++eventHandlers :: [String]+eventHandlers = ["onload","onclick"]; +-- ,"onmousemove","onmouseover","onmousedown","onmouseout","onmouseup","onselectstart", "onkeypress"]++attrScript :: Attribute SourcePos Js.ParsedJavaScript + -> IO [Js.ParsedStatement]+attrScript (Attribute id val loc) | id `elem` eventHandlers = do+ let eventId = drop 2 id -- drop the "on" prefix+ let scriptText = if "javascript:" `isPrefixOf` val then drop 11 val else val+ let eventListenerPrefix = "addEventListener('" ++ eventId ++ "', function(event) { "+ let prefixLen = length eventListenerPrefix+ let eventListenerText = eventListenerPrefix ++ scriptText ++ " });"+ let parser = do+ setPosition (incSourceColumn loc (-prefixLen))+ Js.parseExpression+ case parse parser (sourceName loc) eventListenerText of+ Left err -> do+ fail $ "Error parsiing JavaScript in an attribute at " ++ show loc +++ "\nThe script was:\n\n" ++ eventListenerText+ Right e -> return [Js.ExprStmt loc e]+attrScript _ = return []++inpageAttrScripts :: Js.ParsedJsHtml -> IO [Js.ParsedStatement]+inpageAttrScripts = everything (liftM2 (++)) (mkQ (return []) attrScript)++inpageScripts :: Js.ParsedJsHtml -> [Js.ParsedStatement]+inpageScripts = everything (++) (mkQ [] scriptText)++parseJsFile path = do+ text <- readFile path+ case Js.parseScriptFromString path text of+ Left err -> fail (show err)+ Right js -> hPutStrLn stderr ("Read file " ++ path) >> return js++-- |Given an HTML page, crawls all external Javascript files and returns a list+-- of statements, concatenated from all files.+getPageJavascript:: Js.ParsedJsHtml -> IO [Js.ParsedStatement]+getPageJavascript page = do+ let importURIs = importedScripts page+ let inpageJs = inpageScripts page+ attrScripts <- inpageAttrScripts page+ importedScripts <- mapM parseJsFile importURIs+ let unScript (Js.Script _ ss) = ss+ return $ (concatMap unScript importedScripts ++ attrScripts) ++ inpageJs++getPageJavaScript:: Js.ParsedJsHtml -> IO [Js.ParsedStatement] -- monomorphism+getPageJavaScript = getPageJavascript
+ src/BrownPLT/JavaScript/Environment.hs view
@@ -0,0 +1,146 @@+module BrownPLT.JavaScript.Environment+ ( 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 BrownPLT.JavaScript.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)++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]+ PostfixExpr _ _ e -> expr e+ PrefixExpr _ _ e -> expr e+ InfixExpr _ _ e1 e2 -> unions [expr e1, expr e2]+ CondExpr _ e1 e2 e3 -> unions [expr e1, expr e2, expr e3]+ AssignExpr _ _ (VarRef _ id) e -> unions [ref id, expr e]+ AssignExpr _ _ e1 e2 -> unions [expr e1, expr e2]+ ParenExpr _ e -> expr e+ ListExpr _ es -> unions (map expr es)+ CallExpr _ e es -> unions [expr e, unions $ map expr es]+ FuncExpr _ args s -> nest $ unions [unions $ map decl args, stmt s]++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 (ForInNoVar id) = ref id+ +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 catches ms ->+ unions [stmt s, unions $ map catchClause catches, 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 s ->+ unions [decl fnId, nest $ unions [unions $ map decl args, stmt s]]++-- |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]+ -> Set String+localVars body = S.fromList (M.keys locals) where+ Partial locals _ _ = unions $ map stmt body
+ src/BrownPLT/JavaScript/HtmlEmbedding.hs view
@@ -0,0 +1,25 @@+module BrownPLT.JavaScript.HtmlEmbedding+ ( JsHtml+ , ParsedJavaScript+ , ParsedJsHtml+ ) where++import BrownPLT.Html.Syntax+import BrownPLT.JavaScript.Parser (parseScript)+import BrownPLT.JavaScript.Syntax (JavaScript)+import BrownPLT.JavaScript.PrettyPrint (javaScript)+import Text.ParserCombinators.Parsec (SourcePos)++type JsHtml a = Html SourcePos (JavaScript a)++type ParsedJavaScript = JavaScript SourcePos++type ParsedJsHtml = JsHtml SourcePos++instance Script ParsedJavaScript where+ prettyPrintScript s = javaScript s+ parseScriptBlock attrs = parseScript+ parseInlineScript = Nothing+ parseAttributeScript = Nothing+ +
+ src/BrownPLT/JavaScript/Instances.hs view
@@ -0,0 +1,294 @@+-- |Instances of 'Foldable' and 'Traversable' for JavaScript's syntax.+module BrownPLT.JavaScript.Instances+ ( -- This module does not export any names.+ ) where++import Prelude hiding (foldr,sequence,mapM)+import qualified Prelude as Prelude++import Data.Foldable (Foldable(..))+import Data.Traversable(Traversable(..))+import Control.Applicative++import BrownPLT.JavaScript.Syntax++yfoldr:: Foldable t => (a -> b -> b) -> b -> Maybe (t a) -> b+yfoldr _ b Nothing = b+yfoldr f b (Just t) = foldr f b t++lfoldr:: Foldable t => (a -> b -> b) -> b -> [t a] -> b+lfoldr f = Prelude.foldr (flip $ foldr f)++ltraverse:: (Traversable t, Applicative f) => (a -> f b) -> [t a] -> f [t b]+ltraverse _ [] = pure []+ltraverse f (a:as) = (:) <$> traverse f a <*> ltraverse f as++ytraverse:: (Traversable t, Applicative f) + => (a -> f b) -> Maybe (t a) -> f (Maybe (t b))+ytraverse _ Nothing = pure Nothing+ytraverse f (Just t) = Just <$> traverse f t++instance Functor Id where+ fmap f (Id a v) = Id (f a) v++instance Functor JavaScript where+ fmap f (Script a stmts) = Script (f a) (map (fmap f) stmts)+ +instance Functor Prop where+ fmap f (PropId a id) = PropId (f a) (fmap f id)+ fmap f (PropString a s) = PropString (f a) s+ fmap f (PropNum a n) = PropNum (f a) n++instance Functor Expression where+ fmap f expression = + case expression of+ StringLit a s -> StringLit (f a) s+ RegexpLit a s g ci -> RegexpLit (f a) s g ci+ NumLit a n -> NumLit (f a) n+ IntLit a n -> IntLit (f a) n+ BoolLit a b -> BoolLit (f a) b+ NullLit a -> NullLit (f a)+ ArrayLit a es -> ArrayLit (f a) (map (fmap f) es)+ ObjectLit a pes -> ObjectLit (f a) (map f' pes) where+ f' (p,e) = (fmap f p, fmap f e)+ ThisRef a -> ThisRef (f a)+ VarRef a id -> VarRef (f a) (fmap f id)+ DotRef a e id -> DotRef (f a) (fmap f e) (fmap f id)+ BracketRef a e1 e2 -> BracketRef (f a) (fmap f e1) (fmap f e2)+ NewExpr a e es -> NewExpr (f a) (fmap f e) (map (fmap f) es)+ PostfixExpr a op e -> PostfixExpr (f a) op (fmap f e)+ PrefixExpr a op e -> PrefixExpr (f a) op (fmap f e)+ InfixExpr a op e1 e2 -> InfixExpr (f a) op (fmap f e1) (fmap f e2)+ CondExpr a e1 e2 e3 -> CondExpr (f a) (fmap f e1) (fmap f e2) (fmap f e3)+ AssignExpr a op e1 e2 -> AssignExpr (f a) op (fmap f e1) (fmap f e2)+ ParenExpr a e -> ParenExpr (f a) (fmap f e)+ ListExpr a es -> ListExpr (f a) (map (fmap f) es)+ CallExpr a e es -> CallExpr (f a) (fmap f e) (map (fmap f) es)+ FuncExpr a args s -> FuncExpr (f a) (map (fmap f) args) (fmap f s)++instance Functor CaseClause where+ fmap f (CaseClause a e ss) = CaseClause (f a) (fmap f e) (map (fmap f) ss)+ fmap f (CaseDefault a ss) = CaseDefault (f a) (map (fmap f) ss)+ +instance Functor CatchClause where+ fmap f (CatchClause a id s) = CatchClause (f a) (fmap f id) (fmap f s)++instance Functor VarDecl where+ fmap f (VarDecl a id Nothing) = VarDecl (f a) (fmap f id) Nothing+ fmap f (VarDecl a id (Just e)) = VarDecl (f a) (fmap f id) (Just $ fmap f e)+ +instance Functor ForInit where+ fmap f NoInit = NoInit+ fmap f (VarInit decls) = VarInit (map (fmap f) decls)+ fmap f (ExprInit e) = ExprInit (fmap f e)++instance Functor ForInInit where+ fmap f (ForInVar id) = ForInVar (fmap f id)+ fmap f (ForInNoVar id) = ForInNoVar (fmap f id)+ +instance Functor Statement where+ fmap f s = + case s of+ BlockStmt a ss -> BlockStmt (f a) (map (fmap f) ss)+ EmptyStmt a -> EmptyStmt (f a)+ ExprStmt a e -> ExprStmt (f a) (fmap f e)+ IfStmt a e s1 s2 -> IfStmt (f a) (fmap f e) (fmap f s1) (fmap f s2)+ IfSingleStmt a e s -> IfSingleStmt (f a) (fmap f e) (fmap f s)+ SwitchStmt a e cs -> SwitchStmt (f a) (fmap f e) (map (fmap f) cs)+ WhileStmt a e s -> WhileStmt (f a) (fmap f e) (fmap f s)+ DoWhileStmt a s e -> DoWhileStmt (f a) (fmap f s) (fmap f e)+ BreakStmt a Nothing -> BreakStmt (f a) Nothing+ BreakStmt a (Just id) -> BreakStmt (f a) (Just (fmap f id))+ ContinueStmt a yid -> ContinueStmt (f a) (yid >>= return.(fmap f))+ LabelledStmt a id s -> LabelledStmt (f a) (fmap f id) (fmap f s)+ ForInStmt a init e s -> ForInStmt (f a) (fmap f init) (fmap f e)+ (fmap f s)+ ForStmt a init yinc ytest body -> + ForStmt (f a) (fmap f init) (yinc >>= return.(fmap f))+ (ytest >>= return.(fmap f)) (fmap f body)+ TryStmt a s cs ys -> + TryStmt (f a) (fmap f s) (map (fmap f) cs) (ys >>= return.(fmap f))+ ThrowStmt a e -> ThrowStmt (f a) (fmap f e)+ ReturnStmt a ye -> ReturnStmt (f a) (ye >>= return.(fmap f))+ WithStmt a e s -> WithStmt (f a) (fmap f e) (fmap f s)+ VarDeclStmt a ds -> VarDeclStmt (f a) (map (fmap f) ds)+ FunctionStmt a id args s -> + FunctionStmt (f a) (fmap f id) (map (fmap f) args) (fmap f s)++instance Foldable Id where+ foldr f b (Id a _) = f a b++instance Foldable Prop where+ foldr f b (PropId a id) = f a (foldr f b id)+ foldr f b (PropString a _) = f a b+ foldr f b (PropNum a _) = f a b+ +instance Foldable Expression where+ -- foldr:: (a -> b -> b) -> b -> Expression a -> b+ foldr f b e =+ case e of+ StringLit a _ -> f a b+ RegexpLit a _ _ _ -> f a b+ NumLit a _ -> f a b+ IntLit a _ -> f a b+ BoolLit a _ -> f a b+ NullLit a -> f a b+ ArrayLit a es -> f a (Prelude.foldr (flip $ foldr f) b es)+ ObjectLit a pes -> f a (Prelude.foldr f' b pes) where+ f' (p,e) b = foldr f (foldr f b e) p+ ThisRef a -> f a b+ VarRef a id -> f a (foldr f b id)+ DotRef a e id -> f a (foldr f (foldr f b id) e)+ BracketRef a e1 e2 -> f a (foldr f (foldr f b e2) e1)+ NewExpr a e es -> f a (foldr f (Prelude.foldr (flip $ foldr f) b es) e)+ PostfixExpr a _ e -> f a $ foldr f b e+ PrefixExpr a _ e -> f a $ foldr f b e+ InfixExpr a _ e1 e2 -> f a $ foldr f (foldr f b e2) e1+ CondExpr a e1 e2 e3 -> f a $ foldr f (foldr f (foldr f b e3) e2) e1+ AssignExpr a _ e1 e2 -> f a $ foldr f (foldr f b e2) e1+ ParenExpr a e -> f a $ foldr f b e+ ListExpr a es -> f a $ Prelude.foldr (flip $ foldr f) b es+ CallExpr a e es -> f a $ foldr f (Prelude.foldr (flip $ foldr f) b es) e+ FuncExpr a args s -> + f a $ Prelude.foldr (flip $ foldr f) (foldr f b s) args++instance Foldable CaseClause where+ foldr f b (CaseClause a e ss) = + f a $ foldr f (Prelude.foldr (flip $ foldr f) b ss) e+ foldr f b (CaseDefault a ss) = f a $ Prelude.foldr (flip $ foldr f) b ss+ +instance Foldable CatchClause where+ foldr f b (CatchClause a id s) = f a $ foldr f (foldr f b s) id++instance Foldable VarDecl where+ foldr f b (VarDecl a id ye) = f a $ foldr f (yfoldr f b ye) id++instance Foldable ForInit where+ foldr f b NoInit = b+ foldr f b (VarInit ds) = Prelude.foldr (flip $ foldr f) b ds+ foldr f b (ExprInit e) = foldr f b e++instance Foldable ForInInit where+ foldr f b (ForInVar id) = foldr f b id+ foldr f b (ForInNoVar id) = foldr f b id++instance Foldable Statement where+ foldr f b statement =+ case statement of+ BlockStmt a ss -> f a $ lfoldr f b ss+ EmptyStmt a -> f a b+ ExprStmt a e -> f a $ foldr f b e+ IfStmt a e s1 s2 -> f a $ foldr f (foldr f (foldr f b s2) s1) e+ IfSingleStmt a e s -> f a $ foldr f (foldr f b s) e+ SwitchStmt a e cs -> f a $ foldr f (lfoldr f b cs) e+ WhileStmt a e s -> f a $ foldr f (foldr f b s) e+ DoWhileStmt a s e -> f a $ foldr f (foldr f b e) s+ BreakStmt a yid -> f a $ yfoldr f b yid+ ContinueStmt a yid -> f a $ yfoldr f b yid+ LabelledStmt a id s -> f a $ foldr f (foldr f b s) id+ ForInStmt a init e s -> f a $ foldr f (foldr f (foldr f b s) e) init+ ForStmt a init ye1 ye2 s ->+ f a $ foldr f (yfoldr f (yfoldr f (foldr f b s) ye2) ye1) init+ TryStmt a s cs ys -> f a $ foldr f (lfoldr f (yfoldr f b ys) cs) s+ ThrowStmt a e -> f a $ foldr f b e+ ReturnStmt a ys -> f a $ yfoldr f b ys+ WithStmt a e s -> f a $ foldr f (foldr f b s) e+ VarDeclStmt a ds -> f a $ lfoldr f b ds+ FunctionStmt a id args s ->+ f a $ lfoldr f (foldr f b s) (id:args)++instance Traversable Id where+ traverse f (Id a v) = Id <$> f a <*> pure v++instance Traversable Prop where+ traverse f (PropId a id) = PropId <$> f a <*> traverse f id+ traverse f (PropString a s) = PropString <$> f a <*> pure s+ traverse f (PropNum a n) = PropNum <$> f a <*> pure n+ +instance Traversable Expression where+ traverse f expression =+ case expression of+ StringLit a s -> StringLit <$> f a <*> pure s+ RegexpLit a s g ci -> RegexpLit <$> f a <*> pure s <*> pure g <*> pure ci+ NumLit a n -> NumLit <$> f a <*> pure n+ IntLit a n -> IntLit <$> f a <*> pure n+ BoolLit a b -> BoolLit <$> f a <*> pure b+ NullLit a -> NullLit <$> f a+ ArrayLit a es -> ArrayLit <$> f a <*> ltraverse f es+ ObjectLit a ps -> ObjectLit <$> f a <*> (zip <$> props' <*> es') where+ (props,es) = unzip ps+ props' = ltraverse f props+ es' = ltraverse f es+ ThisRef a -> ThisRef <$> f a+ VarRef a id -> VarRef <$> f a <*> traverse f id+ DotRef a e id -> DotRef <$> f a <*> traverse f e <*> traverse f id+ BracketRef a e es -> BracketRef <$> f a <*> traverse f e <*> traverse f es+ NewExpr a e es -> NewExpr <$> f a <*> traverse f e <*> ltraverse f es+ PostfixExpr a op e -> PostfixExpr <$> f a <*> pure op <*> traverse f e+ PrefixExpr a op e -> PrefixExpr <$> f a <*> pure op <*> traverse f e+ InfixExpr a op e1 e2 -> InfixExpr <$> f a <*> pure op <*> traverse f e1+ <*> traverse f e2+ CondExpr a e1 e2 e3 ->+ CondExpr <$> f a <*> traverse f e1 <*> traverse f e2 <*> traverse f e3+ AssignExpr a op e1 e2 -> AssignExpr <$> f a <*> pure op <*> traverse f e1+ <*> traverse f e2+ ParenExpr a e -> ParenExpr <$> f a <*> traverse f e+ ListExpr a es -> ListExpr <$> f a <*> ltraverse f es+ CallExpr a e es -> CallExpr <$> f a <*> traverse f e <*> ltraverse f es+ FuncExpr a ids s -> FuncExpr <$> f a <*> ltraverse f ids <*> traverse f s++instance Traversable CaseClause where+ traverse f (CaseClause a e ss) =+ CaseClause <$> f a <*> traverse f e <*> ltraverse f ss+ traverse f (CaseDefault a ss) = + CaseDefault <$> f a <*> ltraverse f ss++instance Traversable CatchClause where+ traverse f (CatchClause a id s) = + CatchClause <$> f a <*> traverse f id <*> traverse f s+ +instance Traversable VarDecl where+ traverse f (VarDecl a id ye) =+ VarDecl <$> f a <*> traverse f id <*> ytraverse f ye++instance Traversable ForInit where+ traverse f NoInit = pure NoInit+ traverse f (VarInit ds) = VarInit <$> ltraverse f ds+ traverse f (ExprInit e) = ExprInit <$> traverse f e++instance Traversable ForInInit where+ traverse f (ForInVar id) = ForInVar <$> traverse f id+ traverse f (ForInNoVar id) = ForInNoVar <$> traverse f id++instance Traversable Statement where+ traverse f statement =+ case statement of+ BlockStmt a ss -> BlockStmt <$> f a <*> ltraverse f ss+ EmptyStmt a -> EmptyStmt <$> f a+ ExprStmt a e -> ExprStmt <$> f a <*> traverse f e+ IfStmt a e s1 s2 ->+ IfStmt <$> f a <*> traverse f e <*> traverse f s1 <*> traverse f s2+ IfSingleStmt a e s ->+ IfSingleStmt <$> f a <*> traverse f e <*> traverse f s+ SwitchStmt a e cs ->+ SwitchStmt <$> f a <*> traverse f e <*> ltraverse f cs+ WhileStmt a e s -> WhileStmt <$> f a <*> traverse f e <*> traverse f s+ DoWhileStmt a s e -> DoWhileStmt <$> f a <*> traverse f s <*> traverse f e+ BreakStmt a yid -> BreakStmt <$> f a <*> ytraverse f yid+ ContinueStmt a yid -> ContinueStmt <$> f a <*> ytraverse f yid+ LabelledStmt a id s -> + LabelledStmt <$> f a <*> traverse f id <*> traverse f s+ ForInStmt a init e s ->+ ForInStmt <$> f a <*> traverse f init <*> traverse f e <*> traverse f s+ ForStmt a init yinc ytest s ->+ ForStmt <$> f a <*> traverse f init <*> ytraverse f yinc + <*> ytraverse f ytest <*> traverse f s+ TryStmt a s cs ys ->+ TryStmt <$> f a <*> traverse f s <*> ltraverse f cs <*> ytraverse f ys+ ThrowStmt a e -> ThrowStmt <$> f a <*> traverse f e+ ReturnStmt a ys -> ReturnStmt <$> f a <*> ytraverse f ys+ WithStmt a e s -> WithStmt <$> f a <*> traverse f e <*> traverse f s+ VarDeclStmt a ds -> VarDeclStmt <$> f a <*> ltraverse f ds+ FunctionStmt a id args s ->+ FunctionStmt <$> f a <*> traverse f id <*> ltraverse f args + <*> traverse f s
+ src/BrownPLT/JavaScript/Lexer.hs view
@@ -0,0 +1,64 @@+{- This isn't a lexer in the sense that it provides a JavaScript token-stream.+ - This module provides character-parsers for various JavaScript tokens.+ -}+module BrownPLT.JavaScript.Lexer(lexeme,identifier,reserved,operator,reservedOp,charLiteral,+ stringLiteral,natural,integer,float,naturalOrFloat,+ decimal,hexadecimal,octal,symbol,whiteSpace,parens,+ braces,brackets,squares,semi,comma,colon,dot,+ identifierStart) where++import Prelude hiding (lex)+import Text.ParserCombinators.Parsec+import qualified Text.ParserCombinators.Parsec.Token as T++identifierStart = (letter <|> oneOf "$_")++javascriptDef =+ T.LanguageDef "/*"+ "*/"+ "//"+ False -- no nested comments+ {- Adapted from syntax/regexps.ss in Dave's code. -}+ identifierStart+ (alphaNum <|> oneOf "$_") -- identifier rest+ (oneOf "{}<>()~.,?:|&^=!+-*/%!") -- operator start+ (oneOf "=<>|&+") -- operator rest+ ["break", "case", "catch", "const", "continue", "debugger", + "default", "delete", "do", "else", "enum", "false", "finally",+ "for", "function", "if", "instanceof", "in", "let", "new", + "null", "return", "switch", "this", "throw", "true", "try", + "typeof", "var", "void", "while", "with"]+ ["|=", "^=", "&=", "<<=", ">>=", ">>>=", "+=", "-=", "*=", "/=", + "%=", "=", ";", ",", "?", ":", "||", "&&", "|", "^", "&", + "===", "==", "=", "!==", "!=", "<<", "<=", "<", ">>>", ">>", + ">=", ">", "++", "--", "+", "-", "*", "/", "%", "!", "~", ".", + "[", "]", "{", "}", "(", ")","</","instanceof"]+ True -- case-sensitive+ +lex = T.makeTokenParser javascriptDef++-- everything but commaSep and semiSep+identifier = T.identifier lex+reserved = T.reserved lex+operator = T.operator lex+reservedOp = T.reservedOp lex +charLiteral = T.charLiteral lex +stringLiteral = T.stringLiteral lex +natural = T.natural lex +integer = T.integer lex +float = T.float lex +naturalOrFloat = T.naturalOrFloat lex +decimal = T.decimal lex +hexadecimal = T.hexadecimal lex +octal = T.octal lex +symbol = T.symbol lex +whiteSpace = T.whiteSpace lex +parens = T.parens lex+braces = T.braces lex+squares = T.squares lex +semi = T.semi lex+comma = T.comma lex+colon = T.colon lex +dot = T.dot lex+brackets = T.brackets lex+lexeme = T.lexeme lex
+ src/BrownPLT/JavaScript/Parser.hs view
@@ -0,0 +1,668 @@+module BrownPLT.JavaScript.Parser+ (parseScript+ , parseExpression+ , parseString+ , parseScriptFromString+ , emptyParsedJavaScript+ , ParsedStatement+ , ParsedExpression+ , parseJavaScriptFromFile+ , parseSimpleExpr'+ , parseBlockStmt+ , parseStatement+ , StatementParser+ , ExpressionParser+ , parseAssignExpr+ ) where++import BrownPLT.JavaScript.Lexer hiding (identifier)+import qualified BrownPLT.JavaScript.Lexer as Lexer+import BrownPLT.JavaScript.Syntax+import Text.ParserCombinators.Parsec+import Text.ParserCombinators.Parsec.Expr+import Control.Monad(liftM,liftM2)+import Control.Monad.Trans (MonadIO,liftIO)+import Numeric(readDec,readOct,readHex)+import Data.Char(chr)+import Data.Char++-- We parameterize the parse tree over source-locations.+type ParsedStatement = Statement SourcePos+type ParsedExpression = Expression SourcePos+++-- These parsers can store some arbitrary state+type StatementParser state = CharParser state ParsedStatement+type ExpressionParser state = CharParser state ParsedExpression++identifier =+ liftM2 Id getPosition Lexer.identifier++--{{{ Statements++-- Keep in mind that Token.reserved parsers (exported from the lexer) do not+-- consume any input on failure. Note that all statements (expect for labelled+-- and expression statements) begin with a reserved-word. If we fail to parse+-- this reserved-word, no input is consumed. Hence, we can have the massive or+-- block that is parseExpression. Note that if the reserved-word is parsed, it +-- must be whatever statement the reserved-word indicates. If we fail after the+-- reserved-word, we truly have a syntax error. Since input has been consumed,+-- <|> will not try its alternate in parseExpression, and we will fail.++parseIfStmt:: StatementParser st +parseIfStmt = do+ pos <- getPosition+ reserved "if"+ test <- parseParenExpr <?> "parenthesized test-expression in if statement"+ consequent <- parseStatement <?> "true-branch of if statement"+ optional semi -- TODO: in spec?+ ((do reserved "else"+ alternate <- parseStatement+ return (IfStmt pos test consequent alternate))+ <|> return (IfSingleStmt pos test consequent))++parseSwitchStmt:: StatementParser st+parseSwitchStmt =+ let parseDefault = do+ pos <- getPosition+ reserved "default"+ colon+ statements <- many parseStatement+ return (CaseDefault pos statements)+ parseCase = do+ pos <- getPosition+ reserved "case"+ condition <- parseListExpr+ colon+ actions <- many parseStatement+ return (CaseClause pos condition actions)+ in do pos <- getPosition+ reserved "switch"+ test <- parseParenExpr+ clauses <- braces $ many $ parseDefault <|> parseCase+ return (SwitchStmt pos test clauses)++parseWhileStmt:: StatementParser st+parseWhileStmt = do+ pos <- getPosition+ reserved "while"+ test <- parseParenExpr <?> "parenthesized test-expression in while loop"+ body <- parseStatement+ return (WhileStmt pos test body)++parseDoWhileStmt:: StatementParser st+parseDoWhileStmt = do+ pos <- getPosition+ reserved "do"+ body <- parseBlockStmt+ reserved "while" <?> "while at the end of a do block"+ test <- parseParenExpr <?> "parenthesized test-expression in do loop"+ optional semi+ return (DoWhileStmt pos body test)++parseContinueStmt:: StatementParser st+parseContinueStmt = do+ pos <- getPosition+ reserved "continue"+ pos' <- getPosition+ -- Ensure that the identifier is on the same line as 'continue.'+ id <- (if (sourceLine pos == sourceLine pos')+ then (liftM Just identifier) <|> (return Nothing)+ else return Nothing)+ return (ContinueStmt pos id)++parseBreakStmt:: StatementParser st+parseBreakStmt = do+ pos <- getPosition+ reserved "break"+ pos' <- getPosition+ -- Ensure that the identifier is on the same line as 'break.'+ id <- (if (sourceLine pos == sourceLine pos')+ then (liftM Just identifier) <|> (return Nothing)+ else return Nothing)+ optional semi + return (BreakStmt pos id)++parseBlockStmt:: StatementParser st+parseBlockStmt = do+ pos <- getPosition+ statements <- braces (many parseStatement)+ return (BlockStmt pos statements)++parseEmptyStmt:: StatementParser st +parseEmptyStmt = do+ pos <- getPosition+ semi+ return (EmptyStmt pos)++parseLabelledStmt:: StatementParser st+parseLabelledStmt = do+ pos <- getPosition+ -- Lookahead for the colon. If we don't see it, we are parsing an identifier+ -- for an expression statement.+ label <- try (do label <- identifier+ colon+ return label)+ statement <- parseStatement+ return (LabelledStmt pos label statement)++parseExpressionStmt:: StatementParser st+parseExpressionStmt = do+ pos <- getPosition+ expr <- parseListExpr -- TODO: spec 12.4?+ optional semi+ return (ExprStmt pos expr)+++parseForInStmt:: StatementParser st+parseForInStmt =+ let parseInit = (reserved "var" >> liftM ForInVar identifier)+ <|> (liftM ForInNoVar identifier)+ in do pos <- getPosition+ -- Lookahead, so that we don't clash with parseForStmt+ (init,expr) <- try (do reserved "for"+ parens (do init <- parseInit+ reserved "in"+ expr <- parseExpression+ return (init,expr)))+ body <- parseStatement+ return (ForInStmt pos init expr body) ++parseForStmt:: StatementParser st+parseForStmt =+ let parseInit =+ (reserved "var" >> liftM VarInit (parseVarDecl `sepBy` comma)) <|>+ (liftM ExprInit parseListExpr) <|>+ (return NoInit)+ in do pos <- getPosition+ reserved "for"+ reservedOp "("+ init <- parseInit+ semi+ test <- (liftM Just parseExpression) <|> (return Nothing)+ semi+ iter <- (liftM Just parseListExpr) <|> (return Nothing)+ reservedOp ")" <?> "closing paren"+ stmt <- parseStatement+ return (ForStmt pos init test iter stmt)++parseTryStmt:: StatementParser st+parseTryStmt =+ let parseCatchClause = do+ pos <- getPosition+ reserved "catch"+ id <- parens identifier+ stmt <- parseStatement+ return (CatchClause pos id stmt)+ in do reserved "try"+ pos <- getPosition+ guarded <- parseStatement+ catches <- many parseCatchClause+ finally <- (reserved "finally" >> liftM Just parseStatement) + <|> (return Nothing)+ return (TryStmt pos guarded catches finally)++parseThrowStmt:: StatementParser st+parseThrowStmt = do+ pos <- getPosition+ reserved "throw"+ expr <- parseExpression+ optional semi+ return (ThrowStmt pos expr)++parseReturnStmt:: StatementParser st+parseReturnStmt = do+ pos <- getPosition+ reserved "return"+ expr <- (liftM Just parseListExpr) <|> (return Nothing)+ optional semi+ return (ReturnStmt pos expr)++parseWithStmt:: StatementParser st+parseWithStmt = do+ pos <- getPosition+ reserved "with"+ context <- parseParenExpr+ stmt <- parseStatement+ return (WithStmt pos context stmt)++parseVarDecl = do+ pos <- getPosition+ id <- identifier+ init <- (reservedOp "=" >> liftM Just parseExpression) <|> (return Nothing)+ return (VarDecl pos id init)++parseVarDeclStmt:: StatementParser st+parseVarDeclStmt = do + pos <- getPosition+ reserved "var"+ decls <- parseVarDecl `sepBy` comma+ optional semi+ return (VarDeclStmt pos decls)++parseFunctionStmt:: StatementParser st+parseFunctionStmt = do+ pos <- getPosition+ name <- try (reserved "function" >> identifier) -- ambiguity with FuncExpr+ args <- parens (identifier `sepBy` comma)+ body <- parseBlockStmt <?> "function body in { ... }"+ return (FunctionStmt pos name args body)++parseStatement:: StatementParser st+parseStatement = parseIfStmt <|> parseSwitchStmt <|> parseWhileStmt + <|> parseDoWhileStmt <|> parseContinueStmt <|> parseBreakStmt + <|> parseBlockStmt <|> parseEmptyStmt <|> parseForInStmt <|> parseForStmt+ <|> parseTryStmt <|> parseThrowStmt <|> parseReturnStmt <|> parseWithStmt + <|> parseVarDeclStmt <|> parseFunctionStmt+ -- labelled, expression and the error message always go last, in this order+ <|> parseLabelledStmt <|> parseExpressionStmt <?> "statement"++--}}}++--{{{ Expressions++-- References used to construct this stuff:+-- + http://developer.mozilla.org/en/docs/+-- Core_JavaScript_1.5_Reference:Operators:Operator_Precedence+-- + http://www.mozilla.org/js/language/grammar14.html+--+-- Aren't expression tables nice? Well, we can't quite use them, because of +-- JavaScript's ternary (?:) operator. We have to use two expression tables.+-- We use one expression table for the assignment operators that bind looser +-- than ?: (assignTable). The terms of assignTable are ternary expressions +-- (parseTernaryExpr). parseTernaryExpr left-factors the left-recursive+-- production for ?:, and is defined over the second expression table, +-- exprTable, which consists of operators that bind tighter than ?:. The terms+-- of exprTable are atomic expressions, parenthesized expressions, functions and+-- array references.++--{{{ Primary expressions++parseThisRef:: ExpressionParser st+parseThisRef = do+ pos <- getPosition+ reserved "this"+ return (ThisRef pos)++parseNullLit:: ExpressionParser st+parseNullLit = do+ pos <- getPosition+ reserved "null"+ return (NullLit pos)+++parseBoolLit:: ExpressionParser st+parseBoolLit = do+ pos <- getPosition+ let parseTrueLit = reserved "true" >> return (BoolLit pos True)+ parseFalseLit = reserved "false" >> return (BoolLit pos False)+ parseTrueLit <|> parseFalseLit++parseVarRef:: ExpressionParser st+parseVarRef = liftM2 VarRef getPosition identifier++parseArrayLit:: ExpressionParser st+parseArrayLit = liftM2 ArrayLit getPosition (squares (parseExpression `sepBy` comma))+ +parseFuncExpr = do+ pos <- getPosition+ reserved "function"+ args <- parens (identifier `sepBy` comma)+ body <- parseBlockStmt+ return $ FuncExpr pos args body++--{{{ parsing strings++escapeChars =+ [('\'','\''),('\"','\"'),('\\','\\'),('b','\b'),('f','\f'),('n','\n'),+ ('r','\r'),('t','\t'),('v','\v'),('/','/'),(' ',' ')]++allEscapes:: String+allEscapes = map fst escapeChars++parseEscapeChar = do+ c <- oneOf allEscapes+ let (Just c') = lookup c escapeChars -- will succeed due to line above+ return c' ++parseAsciiHexChar = do+ char 'x'+ d1 <- hexDigit+ d2 <- hexDigit+ return ((chr.fst.head.readHex) (d1:d2:""))++parseUnicodeHexChar = do+ char 'u'+ liftM (chr.fst.head.readHex) + (sequence [hexDigit,hexDigit,hexDigit,hexDigit])+ +isWhitespace ch = ch `elem` " \t"+++-- The endWith argument is either single-quote or double-quote, depending on how+-- we opened the string.+parseStringLit' endWith =+ (char endWith >> return "") <|>+ (do try (string "\\'")+ cs <- parseStringLit' endWith+ return $ "'" ++ cs) <|>+ (do char '\\'+ c <- parseEscapeChar <|> parseAsciiHexChar <|> parseUnicodeHexChar <|> + char '\r' <|> char '\n'+ cs <- parseStringLit' endWith+ if c == '\r' || c == '\n' + then return (c:(dropWhile isWhitespace cs)) + else return (c:cs)) <|>+ (liftM2 (:) anyChar (parseStringLit' endWith))++parseStringLit:: ExpressionParser st+parseStringLit = do+ pos <- getPosition+ -- parseStringLit' takes as an argument the quote-character that opened the+ -- string.+ str <- lexeme $ (char '\'' >>= parseStringLit') <|> (char '\"' >>= parseStringLit')+ -- CRUCIAL: Parsec.Token parsers expect to find their token on the first+ -- character, and read whitespaces beyond their tokens. Without 'lexeme'+ -- above, expressions like:+ -- var s = "string" ;+ -- do not parse.+ return $ StringLit pos str++--}}}++parseRegexpLit:: ExpressionParser st+parseRegexpLit = do+ let parseFlags = do+ flags <- many (oneOf "mgi")+ return $ \f -> f ('g' `elem` flags) ('i' `elem` flags) + let parseEscape = char '\\' >> anyChar+ let parseChar = noneOf "/"+ let parseRe = (char '/' >> return "") <|> + (do char '\\'+ ch <- anyChar -- TOOD: too lenient+ rest <- parseRe+ return ('\\':ch:rest)) <|> + (liftM2 (:) anyChar parseRe)+ pos <- getPosition+ char '/'+ pat <- parseRe --many1 parseChar+ flags <- parseFlags+ spaces -- crucial for Parsec.Token parsers+ return $ flags (RegexpLit pos pat)+ +parseObjectLit:: ExpressionParser st+parseObjectLit =+ let parseProp = do+ -- Parses a string, identifier or integer as the property name. I+ -- apologize for the abstruse style, but it really does make the code+ -- much shorter.+ name <- (liftM (uncurry PropString) + (liftM (\(StringLit p s) -> (p,s)) parseStringLit))+ <|> (liftM2 PropId getPosition identifier)+ <|> (liftM2 PropNum getPosition decimal)+ colon+ val <- parseAssignExpr+ return (name,val)+ in do pos <- getPosition+ props <- braces (parseProp `sepEndBy` comma) <?> "object literal"+ return $ ObjectLit pos props++--{{{ Parsing numbers. From pg. 17-18 of ECMA-262.++hexLit = do+ try (string "0x")+ digits <- many1 (oneOf "0123456789abcdefABCDEF")+ [(hex,"")] <- return $ Numeric.readHex digits+ return (True, hex)++-- Creates a decimal value from a whole, fractional and exponent part.+mkDecimal:: Double -> Double -> Int -> Double+mkDecimal w f e =+ if (f >= 1.0)+ then mkDecimal w (f / 10.0) e+ else (w + f) * (10.0 ^^ e)++exponentPart = do+ oneOf "eE"+ (char '+' >> decimal) <|> (char '-' >> negate `fmap` decimal) <|> decimal++--wrap a parser's result in a Just:+jparser p = p >>= (return . Just) ++decLit = + (do whole <- decimal+ mfrac <- option Nothing (jparser (char '.' >> decimal))+ mexp <- option Nothing (jparser exponentPart)+ if (mfrac == Nothing && mexp == Nothing)+ then return (True, fromIntegral whole)+ else return (False, mkDecimal (fromIntegral whole) + (fromIntegral (maybe 0 id mfrac))+ (fromIntegral (maybe 0 id mexp)))) <|>+ (do frac <- char '.' >> decimal+ exp <- option 0 exponentPart+ return (False, mkDecimal 0.0 (fromIntegral frac) (fromIntegral exp)))++parseNumLit:: ExpressionParser st+parseNumLit = do+ pos <- getPosition+ (isint, num) <- lexeme $ hexLit <|> decLit+ notFollowedBy identifierStart <?> "whitespace"+ if isint+ then return $ IntLit pos (round num) + else return $ NumLit pos num+++------------------------------------------------------------------------------+-- Position Helper+------------------------------------------------------------------------------++withPos cstr p = do { pos <- getPosition; e <- p; return $ cstr pos e }++-------------------------------------------------------------------------------+-- Compound Expression Parsers+-------------------------------------------------------------------------------++dotRef e = (reservedOp "." >> withPos cstr identifier) <?> "property.ref"+ where cstr pos key = DotRef pos e key++funcApp e = (parens $ withPos cstr (parseExpression `sepBy` comma)) <?> "(function application)"+ where cstr pos args = CallExpr pos e args++bracketRef e = (brackets $ withPos cstr parseExpression) <?> "[property-ref]"+ where cstr pos key = BracketRef pos e key++-------------------------------------------------------------------------------+-- Expression Parsers+-------------------------------------------------------------------------------++parseParenExpr:: ExpressionParser st+parseParenExpr = withPos ParenExpr (parens parseListExpr)++-- everything above expect functions+parseExprForNew = parseThisRef <|> parseNullLit <|> parseBoolLit <|> parseStringLit + <|> parseArrayLit <|> parseParenExpr <|> parseNewExpr <|> parseNumLit + <|> parseRegexpLit <|> parseObjectLit <|> parseVarRef++-- all the expression parsers defined above+parseSimpleExpr' = parseThisRef <|> parseNullLit <|> parseBoolLit + <|> parseStringLit <|> parseArrayLit <|> parseParenExpr+ <|> parseFuncExpr <|> parseNumLit <|> parseRegexpLit <|> parseObjectLit+ <|> parseVarRef++parseNewExpr =+ (do pos <- getPosition+ reserved "new"+ constructor <- parseSimpleExprForNew Nothing -- right-associativity+ arguments <- (try (parens (parseExpression `sepBy` comma))) <|> (return [])+ return (NewExpr pos constructor arguments)) <|>+ parseSimpleExpr'++parseSimpleExpr (Just e) = (do+ e' <- dotRef e <|> funcApp e <|> bracketRef e+ parseSimpleExpr $ Just e') <|> (return e)+parseSimpleExpr Nothing = do+ e <- parseNewExpr <?> "expression (3)"+ parseSimpleExpr (Just e)++parseSimpleExprForNew (Just e) = (do+ e' <- dotRef e <|> bracketRef e+ parseSimpleExprForNew $ Just e') <|> (return e)+parseSimpleExprForNew Nothing = do+ e <- parseNewExpr <?> "expression (3)"+ parseSimpleExprForNew (Just e)+ +--}}}++makeInfixExpr str constr = Infix parser AssocLeft where+ parser:: CharParser st (Expression SourcePos -> Expression SourcePos -> Expression SourcePos)+ parser = do+ pos <- getPosition+ reservedOp str+ return (InfixExpr pos constr) -- points-free, returns a function++makePrefixExpr str constr = Prefix parser where+ parser = do+ pos <- getPosition+ (reservedOp str <|> reserved str)+ return (PrefixExpr pos constr) -- points-free, returns a function+ +mkPrefix operator constr = Prefix $ do+ pos <- getPosition+ operator+ return (\operand -> PrefixExpr pos constr operand)++makePostfixExpr str constr = Postfix parser where+ parser = do+ pos <- getPosition+ (reservedOp str <|> reserved str)+ return (PostfixExpr pos constr) -- points-free, returns a function++prefixIncDecExpr = do+ pos <- getPosition+ op <- optionMaybe $ (reservedOp "++" >> return PrefixInc) <|>+ (reservedOp "--" >> return PrefixDec)+ case op of+ Nothing -> parseSimpleExpr Nothing+ Just op -> do+ innerExpr <- parseSimpleExpr Nothing -- TODO: must be an l-val, I think+ return (PrefixExpr pos op innerExpr)++-- apparently, expression tables can't handle immediately-nested prefixes++parsePrefixedExpr = do+ pos <- getPosition+ op <- optionMaybe $ (reservedOp "!" >> return PrefixLNot) <|> + (reservedOp "~" >> return PrefixBNot) <|>+ (try (lexeme $ char '-' >> notFollowedBy (char '-')) >>+ return PrefixMinus) <|>+ (try (lexeme $ char '+' >> notFollowedBy (char '+')) >>+ return PrefixPlus) <|>+ (reserved "typeof" >> return PrefixTypeof) <|>+ (reserved "void" >> return PrefixVoid) <|>+ (reserved "delete" >> return PrefixDelete)+ case op of+ Nothing -> prefixIncDecExpr -- new is treated as a simple expr+ Just op -> do+ innerExpr <- parsePrefixedExpr+ return (PrefixExpr pos op innerExpr)++exprTable:: [[Operator Char st ParsedExpression]]+exprTable = + [+ [makePrefixExpr "++" PrefixInc,+ makePostfixExpr "++" PostfixInc],+ [makePrefixExpr "--" PrefixDec,+ makePostfixExpr "--" PostfixDec],+ [makeInfixExpr "*" OpMul, makeInfixExpr "/" OpDiv, makeInfixExpr "%" OpMod],+ [makeInfixExpr "+" OpAdd, makeInfixExpr "-" OpSub],+ [makeInfixExpr "<<" OpLShift, makeInfixExpr ">>" OpSpRShift,+ makeInfixExpr ">>>" OpZfRShift],+ [makeInfixExpr "<" OpLT, makeInfixExpr "<=" OpLEq, makeInfixExpr ">" OpGT,+ makeInfixExpr ">=" OpGEq, + makeInfixExpr "instanceof" OpInstanceof, makeInfixExpr "in" OpIn],+ [makeInfixExpr "&" OpBAnd], + [makeInfixExpr "^" OpBXor], + [makeInfixExpr "|" OpBOr],+ [makeInfixExpr "&&" OpLAnd],+ [makeInfixExpr "||" OpLOr], + [makeInfixExpr "==" OpEq, makeInfixExpr "!=" OpNEq,+ makeInfixExpr "===" OpStrictEq, makeInfixExpr "!==" OpStrictNEq]+ ]+ +parseExpression' = + buildExpressionParser exprTable parsePrefixedExpr <?> "simple expression"++--{{{ Parsing ternary operators: left factored++parseTernaryExpr':: CharParser st (ParsedExpression,ParsedExpression)+parseTernaryExpr' = do+ reservedOp "?"+ l <- parseAssignExpr+ colon+ r <- parseAssignExpr+ return $(l,r)++parseTernaryExpr:: ExpressionParser st+parseTernaryExpr = do+ e <- parseExpression'+ e' <- optionMaybe parseTernaryExpr'+ case e' of+ Nothing -> return e+ Just (l,r) -> do p <- getPosition+ return $ CondExpr p e l r+--}}}++-- Parsing assignment operations.+makeAssignExpr str constr = Infix parser AssocRight where+ parser:: CharParser st (ParsedExpression -> ParsedExpression -> ParsedExpression)+ parser = do+ pos <- getPosition+ reservedOp str+ return (AssignExpr pos constr)++assignTable:: [[Operator Char st ParsedExpression]]+assignTable = [+ [makeAssignExpr "=" OpAssign, makeAssignExpr "+=" OpAssignAdd, + makeAssignExpr "-=" OpAssignSub, makeAssignExpr "*=" OpAssignMul,+ makeAssignExpr "/=" OpAssignDiv, makeAssignExpr "%=" OpAssignMod,+ makeAssignExpr "<<=" OpAssignLShift, makeAssignExpr ">>=" OpAssignSpRShift,+ makeAssignExpr ">>>=" OpAssignZfRShift, makeAssignExpr "&=" OpAssignBAnd,+ makeAssignExpr "^=" OpAssignBXor, makeAssignExpr "|=" OpAssignBOr+ ]]+++parseAssignExpr:: ExpressionParser st+parseAssignExpr = buildExpressionParser assignTable parseTernaryExpr ++parseExpression:: ExpressionParser st+parseExpression = parseAssignExpr++parseListExpr =+ liftM2 ListExpr getPosition (parseAssignExpr `sepBy1` comma)++--}}}++parseScript:: CharParser state (JavaScript SourcePos)+parseScript = do+ whiteSpace+ liftM2 Script getPosition (parseStatement `sepBy` whiteSpace)+ +parseJavaScriptFromFile :: MonadIO m => String -> m [Statement SourcePos]+parseJavaScriptFromFile filename = do+ chars <- liftIO $ readFile filename+ case parse parseScript filename chars of+ Left err -> fail (show err)+ Right (Script _ stmts) -> return stmts+++parseScriptFromString :: String -> String + -> Either ParseError (JavaScript SourcePos)+parseScriptFromString src script = parse parseScript src script++emptyParsedJavaScript = + Script (error "Parser.emptyParsedJavaScript--no annotation") []++parseString :: String -> [Statement SourcePos]+parseString str = case parse parseScript "" str of+ Left err -> error (show err)+ Right (Script _ stmts) -> stmts
+ src/BrownPLT/JavaScript/PrettyPrint.hs view
@@ -0,0 +1,239 @@+-- |Pretty-printing JavaScript.+module BrownPLT.JavaScript.PrettyPrint+ ( stmt+ , expr+ , javaScript+ , renderStatements+ , renderExpression+ ) where++import Text.PrettyPrint.HughesPJ+import BrownPLT.JavaScript.Syntax+++renderStatements :: [Statement a] -> String+renderStatements ss = render (semiSep ss)+++renderExpression :: Expression a -> String+renderExpression e = render (expr e)+++-- Displays the statement in { ... }, unless it already is in a block.+inBlock:: (Statement a) -> Doc+inBlock s@(BlockStmt _ ss) = stmt s+inBlock s = lbrace $+$ nest 2 (stmt s) $+$ rbrace+++-- Displays the expression in ( ... ), unless it already is in parens.+inParens:: (Expression a) -> Doc+inParens e@(ParenExpr _ _) = expr e+inParens e = parens (expr e)++semiSep :: [Statement a] -> Doc+semiSep ss = vcat $ map (\s -> stmt s <> semi) ss+++pp (Id _ str) = text str+++forInit :: ForInit a -> Doc+forInit t = case t of+ NoInit -> empty+ VarInit vs -> text "var" <+> (cat $ punctuate comma $ (map varDecl vs))+ ExprInit e -> expr e+ ++forInInit :: ForInInit a -> Doc +forInInit t = case t of+ ForInVar id -> text "var" <+> pp id+ ForInNoVar id -> pp id+++caseClause :: CaseClause a -> Doc+caseClause (CaseClause _ e ss) =+ text "case" $+$ expr e <+> colon $$ (nest 2 (semiSep ss))+caseClause (CaseDefault _ ss) =+ text "default:" $$ (nest 2 (semiSep ss))+++catchClause :: CatchClause a -> Doc+catchClause (CatchClause _ id s) = text "catch" <+> (parens.pp) id <+> inBlock s+++varDecl :: VarDecl a -> Doc+varDecl (VarDecl _ id Nothing) = pp id+varDecl (VarDecl _ id (Just e)) = pp id <+> equals <+> expr e+++stmt :: Statement a -> Doc+stmt s = case s of+ BlockStmt _ ss -> lbrace $+$ (nest 2 (semiSep ss)) $$ rbrace+ EmptyStmt _ -> semi+ ExprStmt _ e -> expr e+ IfSingleStmt _ test cons -> text "if" <+> inParens test $$ stmt cons+ IfStmt _ test cons alt ->+ text "if" <+> inParens test $$ stmt cons $$ text "else" <+> stmt alt+ SwitchStmt _ e cases ->+ text "switch" <+> inParens e $$ + braces (nest 2 (vcat (map caseClause cases)))+ WhileStmt _ test body -> text "while" <+> inParens test $$ (stmt body)+ ReturnStmt _ Nothing -> text "return"+ ReturnStmt _ (Just e) -> text "return" <+> expr e+ DoWhileStmt _ s e -> text "do" $$ (stmt s <+> text "while" <+> inParens e)+ BreakStmt _ Nothing -> text "break"+ BreakStmt _ (Just label) -> text "break" <+> pp label+ ContinueStmt _ Nothing -> text "continue"+ ContinueStmt _ (Just label) -> text"continue" <+> pp label+ LabelledStmt _ label s -> pp label <> colon $$ stmt s+ ForInStmt p init e body -> + text "for" <+> + parens (forInInit init <+> text "in" <+> expr e) $+$ stmt body+ ForStmt _ init incr test body ->+ text "for" <+> + parens (forInit init <> semi <+> mexpr incr <> semi <+> mexpr test) $$ + stmt body+ TryStmt _ stmt catches finally ->+ text "try" $$ inBlock stmt $$ (vcat (map catchClause catches)) $$+ ppFinally where + ppFinally = case finally of+ Nothing -> empty+ Just stmt -> text "finally" <> inBlock stmt+ ThrowStmt _ e -> text "throw" <+> expr e+ WithStmt _ expr s -> text "with" <+> inParens expr $$ stmt s+ VarDeclStmt _ decls ->+ text "var" <+> (cat $ punctuate comma (map varDecl decls))+ FunctionStmt _ name args s ->+ text "function" <+> pp name <> + (parens $ cat $ punctuate comma (map pp args)) $$ + inBlock s+++prop :: Prop a -> Doc+prop p = case p of+ PropId _ id -> pp id+ PropString _ str -> doubleQuotes (text (jsEscape str))+ PropNum _ n -> text (show n)+++infixOp op = text $ case op of+ OpMul -> "*"+ OpDiv -> "/"+ OpMod -> "%" + OpAdd -> "+" + OpSub -> "-"+ OpLShift -> "<<"+ OpSpRShift -> ">>"+ OpZfRShift -> ">>>"+ OpLT -> "<"+ OpLEq -> "<="+ OpGT -> ">"+ OpGEq -> ">="+ OpIn -> "in"+ OpInstanceof -> "instanceof"+ OpEq -> "=="+ OpNEq -> "!="+ OpStrictEq -> "==="+ OpStrictNEq -> "!=="+ OpBAnd -> "&"+ OpBXor -> "^"+ OpBOr -> "|"+ OpLAnd -> "&&"+ OpLOr -> "||"+++prefixOp op = text $ case op of+ PrefixInc -> "++"+ PrefixDec -> "--"+ PrefixLNot -> "!"+ PrefixBNot -> "~"+ PrefixPlus -> "+"+ PrefixMinus -> "-"+ PrefixTypeof -> "typeof"+ PrefixVoid -> "void"+ PrefixDelete -> "delete"+++postfixOp op = text $ case op of+ PostfixInc -> "++"+ PostfixDec -> "--"+++assignOp op = text $ case op of+ OpAssign -> "="+ OpAssignAdd -> "+="+ OpAssignSub -> "-="+ OpAssignMul -> "*="+ OpAssignDiv -> "/="+ OpAssignMod -> "%="+ OpAssignLShift -> "<<="+ OpAssignSpRShift -> ">>="+ OpAssignZfRShift -> ">>>="+ OpAssignBAnd -> "&="+ OpAssignBXor -> "^="+ OpAssignBOr -> "|="+++-- Based on:+-- http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals+jsEscape:: String -> String+jsEscape "" = ""+jsEscape (ch:chs) = (sel ch) ++ jsEscape chs where+ sel '\b' = "\\b"+ sel '\f' = "\\f"+ sel '\n' = "\\n"+ sel '\r' = "\\r"+ sel '\t' = "\\t"+ sel '\v' = "\\v"+ sel '\'' = "\\'"+ sel '\"' = "\\\""+ sel '\\' = "\\\\"+ sel x = [x]+ -- We don't have to do anything about \X, \x and \u escape sequences.++ +expr :: Expression a -> Doc+expr e = case e of + StringLit _ str -> doubleQuotes (text (jsEscape str))+ RegexpLit _ re global ci -> + text "/" <> text re <> text "/" <> g <> i where+ g = if global then text "g" else empty+ i = if ci then text "i" else empty+ NumLit _ n -> text (show n)+ IntLit _ n -> text (show n)+ BoolLit _ True -> text "true"+ BoolLit _ False -> text "false"+ NullLit _ -> text "null"+ ArrayLit _ es -> brackets $ cat $ punctuate comma (map expr es)+ ObjectLit _ xs -> + braces (hsep (punctuate comma (map pp' xs))) where+ pp' (n,v) = prop n <> colon <+> expr v+ ThisRef _ -> text "this"+ VarRef _ id -> pp id+ DotRef _ e' id -> expr e' <> text "." <> pp id+ BracketRef _ container key -> expr container <> brackets (expr key)+ NewExpr _ constr args -> + text "new" <+> expr constr <> + (parens $ cat $ punctuate comma (map expr args))+ PrefixExpr _ op e' -> prefixOp op <+> expr e'+ PostfixExpr _ op e' -> expr e' <+> postfixOp op+ InfixExpr _ op left right -> expr left <+> infixOp op <+> expr right+ CondExpr _ test cons alt -> + expr test <+> text "?" <+> expr cons <+> colon <+> expr alt+ AssignExpr _ op l r -> expr l <+> assignOp op <+> expr r+ ParenExpr _ e' -> parens (expr e')+ ListExpr _ es -> cat $ punctuate comma (map expr es)+ CallExpr _ f args -> + expr f <> (parens $ cat $ punctuate comma (map expr args))+ FuncExpr _ args body -> + text "function" <+> + (parens $ cat $ punctuate comma (map pp args)) $$ + inBlock body+++mexpr :: Maybe (Expression a) -> Doc+mexpr Nothing = empty+mexpr (Just e) = expr e++javaScript :: JavaScript a -> Doc+javaScript (Script _ ss) = semiSep ss
+ src/BrownPLT/JavaScript/Syntax.hs view
@@ -0,0 +1,121 @@+-- |JavaScript's syntax.+module BrownPLT.JavaScript.Syntax(Expression(..),CaseClause(..),Statement(..),+ InfixOp(..),CatchClause(..),VarDecl(..),JavaScript(..),+ AssignOp(..),Id(..),PrefixOp(..),PostfixOp(..),Prop(..),+ ForInit(..),ForInInit(..),unId) where++import Text.ParserCombinators.Parsec(SourcePos) -- used by data JavaScript+import Data.Generics(Data,Typeable)++data JavaScript a+ -- |A script in <script> ... </script> tags. This may seem a little silly,+ -- but the Flapjax analogue has an inline variant and attribute-inline + -- variant.+ = Script a [Statement a] + deriving (Show,Data,Typeable,Eq,Ord)++data Id a = Id a String deriving (Show,Eq,Ord,Data,Typeable)++unId :: Id a -> String+unId (Id _ s) = s++-- http://developer.mozilla.org/en/docs/+-- Core_JavaScript_1.5_Reference:Operators:Operator_Precedence+data InfixOp = OpLT | OpLEq | OpGT | OpGEq | OpIn | OpInstanceof | OpEq | OpNEq+ | OpStrictEq | OpStrictNEq | OpLAnd | OpLOr + | OpMul | OpDiv | OpMod | OpSub | OpLShift | OpSpRShift+ | OpZfRShift | OpBAnd | OpBXor | OpBOr | OpAdd+ deriving (Show,Data,Typeable,Eq,Ord,Enum)++data AssignOp = OpAssign | OpAssignAdd | OpAssignSub | OpAssignMul | OpAssignDiv+ | OpAssignMod | OpAssignLShift | OpAssignSpRShift | OpAssignZfRShift+ | OpAssignBAnd | OpAssignBXor | OpAssignBOr+ deriving (Show,Data,Typeable,Eq,Ord)++data PrefixOp = PrefixInc | PrefixDec | PrefixLNot | PrefixBNot | PrefixPlus+ | PrefixMinus | PrefixTypeof | PrefixVoid | PrefixDelete+ deriving (Show,Data,Typeable,Eq,Ord)+ +data PostfixOp + = PostfixInc | PostfixDec+ deriving (Show,Data,Typeable,Eq,Ord)+ +data Prop a + = PropId a (Id a) | PropString a String | PropNum a Integer+ deriving (Show,Data,Typeable,Eq,Ord)++data Expression a+ = StringLit a String+ | RegexpLit a String Bool {- global? -} Bool {- case-insensitive? -}+ | NumLit a Double+ | IntLit a Int+ | BoolLit a Bool+ | NullLit a+ | ArrayLit a [Expression a]+ | ObjectLit a [(Prop a, Expression a)]+ | ThisRef a+ | VarRef a (Id a)+ | DotRef a (Expression a) (Id a)+ | BracketRef a (Expression a) {- container -} (Expression a) {- key -}+ | NewExpr a (Expression a) {- constructor -} [Expression a]+ | PostfixExpr a PostfixOp (Expression a)+ | PrefixExpr a PrefixOp (Expression a)+ | InfixExpr a InfixOp (Expression a) (Expression a)+ | CondExpr a (Expression a) (Expression a) (Expression a)+ | AssignExpr a AssignOp (Expression a) (Expression a)+ | ParenExpr a (Expression a)+ | ListExpr a [Expression a]+ | CallExpr a (Expression a) [Expression a]+ | FuncExpr a [(Id a)] (Statement a)+ deriving (Show,Data,Typeable,Eq,Ord)++data CaseClause a + = CaseClause a (Expression a) [Statement a]+ | CaseDefault a [Statement a]+ deriving (Show,Data,Typeable,Eq,Ord)+ +data CatchClause a + = CatchClause a (Id a) (Statement a) + deriving (Show,Data,Typeable,Eq,Ord)++data VarDecl a + = VarDecl a (Id a) (Maybe (Expression a)) + deriving (Show,Data,Typeable,Eq,Ord)+ +data ForInit a+ = NoInit+ | VarInit [VarDecl a]+ | ExprInit (Expression a)+ deriving (Show,Data,Typeable,Eq,Ord)++data ForInInit a+ = ForInVar (Id a)+ | ForInNoVar (Id a)+ deriving (Show,Data,Typeable,Eq,Ord)+ + +data Statement a+ = BlockStmt a [Statement a]+ | EmptyStmt a+ | ExprStmt a (Expression a)+ | IfStmt a (Expression a) (Statement a) (Statement a)+ | IfSingleStmt a (Expression a) (Statement a)+ | SwitchStmt a (Expression a) [CaseClause a]+ | WhileStmt a (Expression a) (Statement a)+ | DoWhileStmt a (Statement a) (Expression a)+ | BreakStmt a (Maybe (Id a))+ | ContinueStmt a (Maybe (Id a))+ | LabelledStmt a (Id a) (Statement a)+ | ForInStmt a (ForInInit a) (Expression a) (Statement a)+ | ForStmt a (ForInit a) + (Maybe (Expression a)) -- increment+ (Maybe (Expression a)) -- test+ (Statement a) -- body+ | TryStmt a (Statement a) {-body-} [CatchClause a] {-catches-}+ (Maybe (Statement a)) {-finally-}+ | ThrowStmt a (Expression a)+ | ReturnStmt a (Maybe (Expression a))+ | WithStmt a (Expression a) (Statement a)+ | VarDeclStmt a [VarDecl a]+ | FunctionStmt a (Id a) {-name-} [(Id a)] {-args-} (Statement a) {-body-}+ deriving (Show,Data,Typeable,Eq,Ord)
− src/WebBits/Common.hs
@@ -1,63 +0,0 @@--- | Defines commonly used datatypes and functions.-module WebBits.Common- ( PrettyPrintable(..)- , L.isPrefixOf- , SourcePos- , sourceName- ) where--import Data.Map (Map)-import Data.Maybe (catMaybes)-import Data.Char (toLower)-import Control.Applicative-import qualified System.IO as IO-import Control.Monad.State.Strict-import Control.Monad.Identity-import qualified Data.List as L-import Data.Generics hiding (GT)-import qualified Data.Foldable as Foldable-import Data.Foldable (Foldable)-import qualified Data.Traversable as Traversable-import Data.Traversable (Traversable, traverse)-import qualified Text.PrettyPrint.HughesPJ as Pp-import Text.ParserCombinators.Parsec.Pos (SourcePos, initialPos, sourceName)--lowercase = map toLower---- | 'PrettyPrintable' makes writing pretty-printing code for large, recursive--- data structures shorter.-class PrettyPrintable a where- pp:: a -> Pp.Doc- -instance PrettyPrintable a => PrettyPrintable (Maybe a) where- pp (Just a) = pp a- pp Nothing = Pp.empty------------------------------------------------------------------------------------- Generics for SourcePos---- | These definitions allow us to use data structures containing 'SourcePos'--- values with generics.---- |We make 'SourcePos' an instance of 'Typeable' so that we can use it with--- generics.-instance Typeable SourcePos where- typeOf _ = - mkTyConApp (mkTyCon "Text.ParserCombinators.Parsec.Pos.SourcePos") []- --- Complete guesswork. It seems to work.-sourcePosDatatype = mkDataType "SourcePos" [sourcePosConstr1]-sourcePosConstr1 = mkConstr sourcePosDatatype "SourcePos" [] Prefix---- |We make 'SourcePos' an instance of 'Typeable' so that we can use it with--- generics.------ This definition is incomplete.-instance Data SourcePos where- -- We treat source locations as opaque. After all, we don't have access to- -- the constructor.- gfoldl k z pos = z pos- toConstr _ = sourcePosConstr1- gunfold = error "gunfold is not defined for SourcePos"- dataTypeOf = error "dataTypeOf is not defined for SourcePos"-
− src/WebBits/Data/Zipper.hs
@@ -1,274 +0,0 @@--- |A zipper for "Data.Tree".-module WebBits.Data.Zipper- ( - -- * Functional zipper- - -- $functionalZipper- - Tree(..)- , Location- , toLocation, fromLocation - , dfsFold - , dfsFoldM- , showTree-- , empty- , up, down, left, right -- Location a -> Location a- , replace- , change- , insertDown, insertLeft, insertRight- , isTop, isChild- , getValue- , subTree- , top- , canGoLeft, canGoRight, canGoUp, canGoDown -- Location a -> Bool- - -- * Imperative tree construction- - -- $treeBuilder- - , ZipperT-- , nest -- Monad m => v -> ZipperT v m a -> ZipperT v m a- , getNode -- Monad m => ZipperT v m v- , setNode -- Monad m => v -> ZipperT v m ()- , runZipperT- , evalZipperT- , execZipperT- , shiftLeft, shiftRight -- Monad m => ZipperT v m ()- , shiftLeft', shiftRight' -- Monad m => ZipperT v m ()- , withCurrentChild -- Monad m => Zipper T v m a -> ZipperT v m a- - ) where--import Control.Monad-import Control.Monad.State-import Data.Tree (Tree (..), drawTree)------------------------------------------------------------------------------------ Data types!-----data Path a- = Top- | Split a [Tree a] (Path a) [Tree a]--data Location a = Location (Tree a) (Path a)---dfsFold :: (w -> v -> w) -- ^transforms a node 'v' using the accumulated- -- value 'w' from the root of the tree to 'v'- -> w -- ^the initial value of the accumulator at the root- -> Tree v - -> Tree w-dfsFold f w (Node v ts) = Node w' (map (dfsFold f w') ts)- where w' = f w v---- |Similar to 'dfsFold', but the transformation is done in the monad 'm'. The--- sequence of operations is depth-first, left-to-right.-dfsFoldM :: Monad m => (w -> v -> m w) -> w -> Tree v -> m (Tree w)-dfsFoldM f w (Node v ts) = do- w' <- f w v- ts' <- mapM (dfsFoldM f w') ts- return $ Node w' ts'---- Uses 'Data.Tree.drawShow'.-showTree :: Show a => Tree a -> String-showTree tree = drawTree (fmap show tree)- ------------------------------------------------------------------------------------ Combinators!------- $functionalZipper--- These are the core zipper functions.--empty :: a -> Tree a-empty a = Node a []--up :: Location a -> Location a-up (Location _ Top) = error " up of Top"-up (Location t (Split v ls p rs)) = Location (Node v (reverse ls ++ (t:rs))) p--down :: Location a -> Location a-down (Location (Node v []) _) = error "down of empty"-down (Location (Node v (t:ts)) p) = Location t (Split v [] p ts)--left :: Location a -> Location a-left (Location t Top) = error "left of top"-left (Location t (Split v [] p rs)) = error "left on leftmost"-left (Location t (Split v (l:ls) p rs)) = Location l (Split v ls p (t:rs))--right :: Location a -> Location a-right (Location t Top) = - error "Data.Zipper.right : at the top"-right (Location t (Split v ls p [])) = error "right on rightmost"-right (Location t (Split v ls p (r:rs))) = Location r (Split v (t:ls) p rs)--replace :: Location a -> Tree a -> Location a-replace (Location _ p) t = Location t p--change :: Location a -> a -> Location a-change (Location (Node _ cs) p) t = Location (Node t cs) p--insertDown :: Location a -> Tree a -> Location a-insertDown (Location (Node v ts) p) t = Location (Node v (t:ts)) p--insertDownRight :: Location a -> Tree a -> Location a-insertDownRight (Location (Node v ts) p) t = - Location t (Split v (reverse ts) p [])--insertLeft :: Location a -> Tree a -> Location a-insertLeft (Location _ Top) _ = error "insert on top"-insertLeft (Location t (Split v ls p rs)) t' =- Location t (Split v (t':ls) p rs)--insertRight :: Location a -> Tree a -> Location a-insertRight (Location _ Top) _ = error "insert on top"-insertRight (Location t (Split v ls p rs)) t' = - Location t (Split v ls p (t':rs))--isTop :: Location a -> Bool-isTop (Location _ Top) = True-isTop _ = False--isChild :: Location a -> Bool-isChild = not . isTop--canGoRight :: Location a -> Bool-canGoRight (Location _ (Split _ _ _ [])) = False-canGoRight (Location _ Top) = False-canGoRight _ = True--canGoDown :: Location a -> Bool-canGoDown (Location (Node _ []) _) = False-canGoDown _ = True--canGoLeft :: Location a -> Bool-canGoLeft (Location _ Top) = False-canGoLeft (Location _ (Split _ [] _ _)) = False-canGoLeft _ = True--canGoUp :: Location a -> Bool-canGoUp (Location _ Top) = False-canGoUp _ = True--getValue :: Location a -> a-getValue (Location (Node v _) _) = v--subTree :: Location a -> Tree a-subTree (Location node _) = node---- |Traverses to the top of the tree.------ @--- up.top = undefined--- top.top = top--- @-top :: Location a -> Location a-top loc@(Location _ Top) = loc-top loc@(Location _ _) = top (up loc)--toLocation :: Tree a -> Location a-toLocation t = Location t Top--fromLocation :: Location a -> Tree a-fromLocation (Location t _) = t----- $treeBuilder--- A state monad that carries a zipper. It provides convenient methods to--- imperatively create and update a tree.------ The state monad's set method may be used to arbitrarily update the current--- location. However, such updates can break the behavior of nest and--- withCurrentChild. We recommend avoiding StateT.set.--type ZipperT v m a = StateT (Location v) m a---runZipperT :: Monad m => ZipperT v m a -> Location v -> m (a, Tree v)-runZipperT m l = do- (a, Location t Top) <- runStateT m l- return (a,t)--evalZipperT :: Monad m => ZipperT v m a -> Location v -> m a-evalZipperT m l = do- ~(a, _) <- runStateT m l- return a--execZipperT :: Monad m => ZipperT v m a -> Location v -> m (Tree v)-execZipperT m l = do- ~(_, Location t Top) <- runStateT m l- return t---- |Creates a new node as the right-most child of the current node.-nest :: Monad m - => v -- ^value of the new right-most child - -> ZipperT v m a -- ^computation applied to the new child - -> ZipperT v m a -- ^returns the result of the nested computation-nest v m = do- z <- get - put $ insertDownRight z (empty v)- a <- m- z' <- get -- z' is the child of z - put (up z')- return a- -getNode :: Monad m => ZipperT v m v-getNode = do- (Location (Node v _) _) <- get- return v- -setNode :: Monad m => v -> ZipperT v m ()-setNode v = do- (Location (Node _ cs) path) <- get- put $ Location (Node v cs) path--withCurrentChild :: Monad m - => ZipperT v m a -- ^computation to apply to the current child - -> ZipperT v m a -- ^returns the result of the nested - -- computation-withCurrentChild m = do- z <- get- put (down z)- a <- m- z' <- get- put (up z')- return a--shiftRight :: Monad m => ZipperT v m ()-shiftRight = do- z <- get- put (right z)-- -shiftLeft :: Monad m => ZipperT v m ()-shiftLeft = do- z <- get- put (left z)---- |Silently fails to shift right if there is no right-child.-shiftRight' :: Monad m => ZipperT v m ()-shiftRight' = do- z <- get- when (hasRight z)- (put (right z))---- |Silently fails to shift left if there is no left-child.-shiftLeft' :: Monad m => ZipperT v m ()-shiftLeft' = do- z <- get- when (hasLeft z)- (put (left z))--hasLeft :: Location a -> Bool-hasLeft (Location _ (Split _ (_:_) _ _)) = True-hasLeft _ = False--hasRight :: Location a -> Bool-hasRight (Location _ (Split _ _ _ (_:_))) = True-hasRight _ = False--
− src/WebBits/Html/Html.hs
@@ -1,14 +0,0 @@--- |Rexports various modules of the HTML library. It's best to use this in lieu--- of selectively importing the following libraries.-module WebBits.Html.Html- ( module WebBits.Html.Syntax- -- PermissiveParser- , html- , parseHtmlFromFile- , parseHtmlFromString- ) where- -import WebBits.Html.Syntax-import WebBits.Html.PermissiveParser-import WebBits.Html.PrettyPrint -- no names, only instances-import WebBits.Html.Instances -- no names, only instances
− src/WebBits/Html/Instances.hs
@@ -1,66 +0,0 @@-module WebBits.Html.Instances() where--import qualified Prelude as Prelude-import Prelude (Functor,map,fmap)-import qualified Data.List as List-import qualified Data.Char as Char-import Data.Foldable-import Data.Traversable-import Control.Applicative--import WebBits.Html.Syntax--ltraverse:: (Traversable t, Applicative f) => (a -> f b) -> [t a] -> f [t b]-ltraverse f [] = pure []-ltraverse f (x:xs) = pure (:) <*> (traverse f x) <*> ltraverse f xs--instance Functor (Attribute a) where- fmap f (Attribute id val a) = Attribute id val a- fmap f (AttributeExpr a id script def) = AttributeExpr a id (f script) def--instance Functor (Html a) where- fmap f (Element id attrs children a) = - Element id (map (fmap f) attrs) (map (fmap f) children) a- fmap f (Text str a) = Text str a- fmap f (Comment str a) = Comment str a- fmap f (HtmlSeq xs) = HtmlSeq (map (fmap f) xs)- fmap f (ProcessingInstruction str a) = ProcessingInstruction str a- fmap f (InlineScript script a def) = InlineScript (f script) a def- fmap f (Script script a) = Script (f script) a--instance Foldable (Attribute a) where- foldr f x (Attribute id val a) = x- foldr f x (AttributeExpr a id script def) = f script x--instance Foldable (Html a) where- foldr f x (Element id attrs children a) =- Prelude.foldr (\child x' -> foldr f x' child) x children - foldr f x (Text str a) = x- foldr f x (Comment str a) = x- foldr f x (HtmlSeq ys) = - Prelude.foldr (\child x' -> foldr f x' child) x ys- foldr f x (ProcessingInstruction str a) = x- foldr f x (InlineScript script a def) = f script x- foldr f x (Script script a) = f script x--instance Traversable (Attribute a) where- traverse f (Attribute id val a) =- pure (Attribute id val a)- traverse f (AttributeExpr a id script def) =- (AttributeExpr a id) <$> (f script) <*> pure def--instance Traversable (Html a) where- traverse f (Element id attrs children a) = - (Element id) <$> ltraverse f attrs <*> ltraverse f children <*> pure a- traverse f (Text str a) = - pure (Text str a)- traverse f (Comment str a) = - pure (Comment str a)- traverse f (HtmlSeq xs) = - HtmlSeq <$> ltraverse f xs- traverse f (ProcessingInstruction str a) = - pure (ProcessingInstruction str a)- traverse f (InlineScript script a def) =- InlineScript <$> (f script) <*> pure a <*> pure def- traverse f (Script script a) = - Script <$> (f script) <*> pure a
− src/WebBits/Html/PermissiveParser.hs
@@ -1,492 +0,0 @@--- |A structure-recovering parser for malformed documents.------ Copyright 2007-2008 Arjun Guha.--- Based on HtmlPrag 0.16 Copyright (C) 2003 - 2005 Neil W. Van Dyke. ------ This program is Free Software; you can redistribute it and/or modify it under--- the terms of the GNU Lesser General Public License as published by the Free--- Software Foundation; either version 2.1 of the License, or (at your option)--- any later version. This program is distributed in the hope that it will be--- useful, but without any warranty; without even the implied warranty of--- merchantability or fitness for a particular purpose. See --- <http://www.gnu.org/copyleft/lesser.html> for details. For other license--- options and consulting, contact the author.-module WebBits.Html.PermissiveParser- ( html- , parseHtmlFromFile- , parseHtmlFromString- -- tokenizer is exported primarily for testing- , tokens- , Token- ) where--import Control.Monad-import Text.ParserCombinators.Parsec hiding (token,tokens)-import qualified Text.ParserCombinators.Parsec as Parsec-import Data.Char (toLower)-import Data.List (intersperse)--import qualified WebBits.Html.Syntax as Html-import WebBits.Html.Syntax (HtmlId,Attribute,Script(..))--type ParsedHtml s = Html.Html SourcePos s-type ParsedAttribute s = Html.Attribute SourcePos s------------------------------------------------------------------------------------- Parsers generate warnings--data Warning = StringWarning SourcePos String--instance Show Warning where- show (StringWarning p s) = "Warning parsing HTML: " ++ s- showList [] s = s- showList (x:xs) s = show x ++ ('\n':showList xs s)--warn:: String -> GenParser tok [Warning] ()-warn s = do- p <- getPosition- updateState ((StringWarning p s):)--noWarnings:: [Warning]-noWarnings = []- ---- A structure-recovering parser for malformed documents, derived from--- Neil W. Van Dyke's htmlprag library for PLT Scheme---- The elements in the list can legally enclose the 1st element of the pair.-parentConstraints:: [(HtmlId,[HtmlId])]-parentConstraints =- [("area",["map"]),- ("body",["html"]),- ("caption", ["table"]),- ("colgroup", ["table"]),- ("dd", ["dl"]),- ("dt", ["dl"]),- ("frame", ["frameset"]),- ("head", ["html"]),- ("isindex", ["head"]),- ("li", ["dir", "menu", "ol", "ul"]),- ("meta", ["head"]),- ("noframes", ["frameset"]),- ("option", ["select"]),- ("p", ["body", "td", "th"]),- ("param", ["applet"]),- ("tbody", ["table"]),- ("td", ["tr"]),- ("th", ["tr"]),- ("thead", ["table"]),- ("title", ["head"]),- ("tr", ["table", "tbody", "thead"])]---- |List of HTML elements that are empty.-emptyElements:: [HtmlId]-emptyElements = - ["area", "base", "br", "frame", "hr", "img", "input", "isindex", "keygen", - "link", "meta", "object", "param", "spacer", "wbr"]--isLegalChildOf:: HtmlId -> HtmlId -> Bool-isLegalChildOf child parent =- case lookup child parentConstraints of- Nothing -> True- (Just legalParents) -> parent `elem` legalParents- -isEmptyElement:: HtmlId -> Bool-isEmptyElement element = element `elem` emptyElements----}}}------------------------------------------------------------------------------------- Parses an HTML file into a stream of tokens.---- The auxillary parsing functions return values of this type.-data Script s => Token s- = Text SourcePos String- | EntityToken SourcePos String- | EntityInt SourcePos Int- | Tag SourcePos HtmlId [Attribute SourcePos s] Bool {-closed?-}- | Script SourcePos s- | Inline SourcePos s String- | EndTag SourcePos HtmlId- | Comment SourcePos String- | DoctypeToken SourcePos String String String (Maybe String)---token:: Script s => Bool -> [Attribute SourcePos s] - -> CharParser [Warning] (Token s)-token expectedScript prevAttrs = case expectedScript of- True -> (liftM2 Script getPosition (parseScriptBlock prevAttrs)) - <?> "expected a script after a <script> tag"- False -> doctype <|> comment <|> tag <|> endTag <|> inlineScript <|> entity - <|> text--tokens:: Script s => CharParser [Warning] [Token s]-tokens = (eof >> return []) <|> tokens' where- tokens' = do - t <- token False []- case t of- (Tag _ "script" attrs False) -> do s <- token True attrs- ts <- tokens- return (t:s:ts)- _ -> tokens >>= return.(t:)------------------------------------------------------------------------------------- Parsers for various components of HTML--qname:: CharParser st String-qname = do- x <- letter- xs <- many (noneOf "/*=<>\"\' \v\f\t\r\n")- return (x:xs)---- |We do not permit spaces between the hyphens and the right-angle in the--- terminating '-->'.-comment:: Script s => CharParser st (Token s) -comment =- let notDoubleHyphen = try (char '-' >> notFollowedBy (char '-') >> return '-')- notHyphen = noneOf "-"- in do try (string "<!--")- pos <- getPosition- msg <- many (notHyphen <|> notDoubleHyphen)- string "-->"- return (Comment pos msg)--endTag:: Script s => CharParser [Warning] (Token s)-endTag = do- pos <- getPosition- string "</"- name <- qname <?> "closing tag\'s name"- junk <- manyTill anyChar (char '>') -- permits junk between tag name and '>'- unless (null junk) (warn $ "extra characters: " ++ junk ++ - "; assuming tag name is " ++ name)- return (EndTag pos name)- -doctype:: Script s => CharParser [Warning] (Token s)-doctype = do- p <- getPosition- try (string "<!DOCTYPE")- spaces- top <- qname <?> "top-element name"- spaces- avail <- qname <?> "availability"- spaces- regEtc <- quotedString <?> "registration, etc."- spaces- uri <- optionMaybe quotedString- spaces- string ">"- return (DoctypeToken p top avail regEtc uri)- -entity:: Script s => CharParser [Warning] (Token s)-entity = do- char '&'- pos <- getPosition- name <- many alphaNum <|> (char '#' >> many1 digit)- when (null name) (warn "no identifer or number after &")- (char ';' >> return ()) <|> (warn "expected semi-colon after entity") - return (EntityToken pos name)- -notScript:: CharParser a Char-notScript = try (char '{' >> notFollowedBy (char '!') >> return '{')---- Parses raw text, upto an opening angle-bracket ('<').-text:: Script s => CharParser st (Token s)-text = do- pos <- getPosition- cs <- many1 (noneOf "<{" <|> notScript) -- Doesn't consume the terminating angle bracket.- return (Text pos cs)---- Strings that are either double-quoted or single-quoted. Note that HTML--- strings contain no escape sequences.-quotedString:: CharParser a String-quotedString =- (char '"' >> manyTill anyChar (char '"')) <|>- (char '\'' >> manyTill anyChar (char '\'')) <?>- "quoted string (double-quotes or single quotes)"---- Parses text to the right of a triple-stick in an inline expression. We have--- to ensure that if we read a `!,' it isn't immediately followed by `}.'-initText =- let notEnd = try (char '!' >> notFollowedBy (char '}') >> return '!')- in many1 (notEnd <|> noneOf "!")--scriptValue:: Script s => CharParser a (s,String)-scriptValue =- case parseAttributeScript of- Nothing -> fail "attribute-script parser not defined"- (Just parser) -> do string "{!"- script <- parser- init <- (string "!}" >> return "") <|> - (string "|||" >> initText >>= - (\s -> string "!}" >> return s))- return (script,init)--number:: CharParser a String-number = many1 digit---- -nonquotedAttribute:: CharParser [Warning] String-nonquotedAttribute = do- x <- alphaNum <|> oneOf "_"- xs <- many (noneOf "/*=<>\"\' \v\f\t\r\n")- warn $ "non-quoted attribute value: " ++ (x:xs)- return (x:xs)---attribute:: Script s => CharParser [Warning] (Html.Attribute SourcePos s)-attribute = do- pos <- getPosition- name <- qname <?> "attribute name"- spaces- value <- (do char '='- spaces- (liftM Right scriptValue)- <|> (liftM Left (quotedString <|> nonquotedAttribute)) - <?> "attribute value")- <|> (return $ Left "") -- Unspecified values are empty values.- case value of- (Left v) -> return $ Html.Attribute name v pos- (Right (s,d)) -> return $ Html.AttributeExpr pos name s d---- Takes the name of the immediately-enclosing parent tag as an argument.-tag:: Script s => CharParser [Warning] (Token s)-tag = do- try (char '<' >> notFollowedBy (char '/'))- pos <- getPosition- name <- qname <?> "opening tag\'s name"- spaces- attributes <- (attribute `sepEndBy` spaces)- (char '>' >> return (Tag pos name attributes False))- <|> (string "/>" >> return (Tag pos name attributes True))- <?> "end of tag (i.e. \">\")"----- Parses an inline (curly-banged) script, if an inline-script parser has been--- specified (i.e. not Nothing). Two-character lookahead for the ``{!,'' after--- which control is passed to the inline script parser. Once control returns,--- the parser expects to see the closing ``!}.''-inlineScript:: Script s => CharParser a (Token s)-inlineScript =- case parseInlineScript of- Nothing -> fail "no inline script parser specified." -- TODO: appropriate?- (Just parser) -> do string "{!" <?> "{! script !}"- pos <- getPosition- script <- parser- spaces- init <- (string "!}" >> return "") <|>- (string "|||" >> initText >>= - (\s -> string "!}" >> return s))- return $ Inline pos script init----- Parses a stream of tokens, with a script parser, s and returns values of --- type a.-type TokenParser s a = GenParser (Token s) [Warning] a--instance Script s => Show (Token s) where- show = tokenShow--tokenShow token = case token of- (Text _ s) -> s- (EntityToken _ s) -> "&" ++ s ++ ";"- (EntityInt _ n) -> "&#" ++ show n ++ ";"- (Tag _ id attrs closed) -> - "<" ++ id ++ " ... " ++ closing where- closing = if closed then "/>" else ">"- (Script _ s) -> "/* script body omitted */"- (Inline _ s _)-> "{! /* script */ !}"- (EndTag _ id) -> "</" ++ show id ++ ">"- (Comment _ s) -> "<!-- " ++ show s ++ " -->"- (DoctypeToken _ top avail desc Nothing) ->- "<!DOCTYPE " ++ top ++ " " ++ avail ++ " " ++ show desc ++ ">"- (DoctypeToken _ top avail desc (Just uri)) ->- "<!DOCTYPE " ++ top ++ " " ++ avail ++ " " ++ show desc ++ " " - ++ show uri ++ ">" --tokenPos tok = case tok of- (Text p _) -> p- (EntityToken p _) -> p- (EntityInt p _) -> p- (Tag p _ _ _) -> p- (Script p _) -> p- (Inline p _ _) -> p- (EndTag p _) -> p- (Comment p _) -> p- (DoctypeToken p _ _ _ _) -> p- -textToken :: Script s => TokenParser s (ParsedHtml s)-textToken = Parsec.token tokenShow tokenPos $ \t -> case t of- Text _ s -> Just (Html.Text s (tokenPos t))- otherwise -> Nothing- -entityToken :: Script s => TokenParser s (ParsedHtml s)-entityToken =- Parsec.token tokenShow tokenPos- (\t -> case t of- (EntityToken p s) -> Just (Html.Text ("&" ++ s ++ ";") p)- (EntityInt p n) -> Just (Html.Text ("&#" ++ show n ++ ";") p)- otherwise -> Nothing)- -commentToken :: Script s => TokenParser s (ParsedHtml s)-commentToken = - Parsec.token tokenShow tokenPos- (\t -> case t of- (Comment _ s) -> Just (Html.Comment s (tokenPos t))- otherwise -> Nothing)--scriptToken :: Script s => TokenParser s (ParsedHtml s) -scriptToken = - Parsec.token tokenShow tokenPos- (\t -> case t of- (Script p s) -> Just (Html.Script s p)- otherwise -> Nothing)--inlineToken :: Script s => TokenParser s (ParsedHtml s)-inlineToken = - Parsec.token tokenShow tokenPos- (\t -> case t of- (Inline p s d) -> Just (Html.InlineScript s p d)- otherwise -> Nothing)- -endToken :: Script s => TokenParser s HtmlId-endToken = - Parsec.token tokenShow tokenPos- (\t -> case t of- (EndTag p s) -> Just s- otherwise -> Nothing)--tagToken :: Script s => TokenParser s (Token s)-tagToken = - Parsec.token tokenShow tokenPos- (\t -> case t of- (Tag p id attrs closed) -> Just t- otherwise -> Nothing)--doctypeToken :: Script s => TokenParser s (Token s)-doctypeToken = Parsec.token tokenShow tokenPos $ \t -> case t of- DoctypeToken _ _ _ _ _ -> Just t- otherwise -> Nothing------------------------------------------------------------------------------------- HTML fragments---- |An HTML fragment represents an HTML element with a sequence of children.-data HtmlFragment s = Fragment {- fragmentPosition :: SourcePos,- fragmentName :: HtmlId,- fragmentAttributes :: [ParsedAttribute s],- fragmentChildren :: [ParsedHtml s]-}--closeFragment:: HtmlFragment s -> ParsedHtml s-closeFragment (Fragment p htmlId attrs children) = - Html.Element htmlId attrs (reverse children) p--appendChildToFragment child fragment =- fragment { fragmentChildren = child : (fragmentChildren fragment) }- -atomic :: Script s => TokenParser s (ParsedHtml s)-atomic =- textToken <|> commentToken <|> scriptToken <|> inlineToken <|> entityToken---maybeClose :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s] -maybeClose es = do- htmlId <- endToken- let close [] = do - warn $ "unmatched closing tag \"" ++ htmlId ++ "\"; ignoring"- return es- close (e:e2:es) | fragmentName e == htmlId = do- return $ (appendChildToFragment (closeFragment e) e2) : es- close (e:e2:es) | otherwise = - let e2' = appendChildToFragment (closeFragment e) e2- in close (e2':es)- close [e] | fragmentName e == htmlId = do- return [e]- close [e] | otherwise = do- warn $ "unmatched closing tag \"" ++ htmlId ++ "\"; ignoring"- return [e]- in close es--open :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s]-open [] = fail "PermissiveParser.open: invalid state (1)"-open (e:es) = do- (Tag p id attrs isClosed) <- tagToken- case isClosed of- True -> return $ (appendChildToFragment (Html.Element id attrs [] p) e) : es- False ->- case isEmptyElement id of- True -> do warn $ "empty-element, \"" ++ id - ++ "\" was not immediately closed"- return $ (appendChildToFragment (Html.Element id attrs [] p)- e) : es- False -> do- let fragment = Fragment p id attrs []- -- If we reach the root, simply make 'fragment' a child.- let insert [root] = [fragment,root]- -- The <html> element is the only child of the root. This- -- catches all other elements and makes them children of <html>.- insert [html,root] = [fragment,html,root]- insert (e1:e2:es) | id `isLegalChildOf` (fragmentName e1) =- fragment:e1:e2:es- insert (e1:e2:es) | otherwise =- insert $ (appendChildToFragment (closeFragment e1) e2):es - insert [] = fail "PermissiveParser.open: invalid state (2)"- return $ insert (e:es)--structured es = do- maybeClose es <|> open es--html' :: Script s => [HtmlFragment s] -> TokenParser s [HtmlFragment s]-html' [] = fail "PermissiveParser.html': invalid state (1)"-html' (e:es) =- (do a <- atomic- html' $ (appendChildToFragment a e):es) <|>- (structured (e:es) >>= html') <|>- (return (e:es))--parseRoot = Fragment (error "parseRoot: position is meaningless") - "DOCROOT" (error "parseRoot: attributes are meaningless")- []--html :: Script s => CharParser [Warning] (Html.Html SourcePos s)-html = do- let parser = do- -- optional doctypeToken -- ignored- fragments <- html' [parseRoot]- case fragments of- [fragment] -> case closeFragment fragment of - Html.Element _ _ (c:_) _ -> do- ws <- getState- return (ws,head [c])- otherwise -> fail "root element not found"- otherwise -> fail "no root / multiple roots"- toks <- tokens -- a stream of HTML entities- pos <- Parsec.getPosition- warnings <- Parsec.getState- case Parsec.runParser parser warnings (Parsec.sourceName pos) toks of- Left e -> fail $ "unparsable HTML: " ++ (show e)- Right (ws,html) -> Parsec.setState ws >> return html --htmlWithWarnings :: Script s - => CharParser [Warning] (Html.Html SourcePos s,[Warning])-htmlWithWarnings = do- h <- html- ws <- getState- return (h,ws)--parseHtmlFromString :: Script s => String -> String -> Either Parsec.ParseError (Html.Html SourcePos s,[Warning])-parseHtmlFromString sourceName sourceText = - case Parsec.runParser htmlWithWarnings noWarnings sourceName sourceText of- Left err -> Left err- Right (html,ws) -> Right (html,ws) --parseHtmlFromFile :: Script s - => String - -> IO (Either Parsec.ParseError - (Html.Html SourcePos s,[Warning]))-parseHtmlFromFile filename = do- chars <- readFile filename- case Parsec.runParser htmlWithWarnings noWarnings filename chars of- Left err -> return (Left err)- Right (html,ws) -> return $ Right (html,ws)
− src/WebBits/Html/PrettyPrint.hs
@@ -1,54 +0,0 @@--- |Pretty-printer for HTML. This modules exports no names. It only defines--- instances of 'PrettyPrintable' for HTML. -module WebBits.Html.PrettyPrint- ( -- this module exports no names- ) where--import qualified Data.List as List-import qualified Data.Char as Char-import Text.PrettyPrint.HughesPJ--import WebBits.Common (PrettyPrintable(..))--import WebBits.Html.Syntax--vert [] = empty-vert [doc] = doc-vert (doc:docs) = doc <> text "<!--" $+$- text "-->" <> vert docs--instance PrettyPrintable s => PrettyPrintable (Attribute a s) where- pp (Attribute name value _) =- text name <> equals <> doubleQuotes (text value)- pp (AttributeExpr _ n v "") =- text n <> equals <> text "{!" <+> pp v <+> text "!}"- pp (AttributeExpr _ n v d) =- text n <> equals <> text "{!" <+> pp v <+> text "|||" <+> text d - <+> text "!}"--instance PrettyPrintable s => PrettyPrintable (Html a s) where- -- The <script> tag must be terminated by </script>.- -- <script lang= src= /> doesn't work.- -- pp (Element name attrs [] _) =- -- text "<" <> text name <+> hsep (map pp attrs) <+> text "/>"- pp (Element name attrs children _) =- -- WARNING: Spacing is very sensitive- text "<" <> text name <+> hsep (map pp attrs) <> text ">" -- opening- $$ (nest 2 (vcat (map pp children))) -- body- $$ text "</" <> text name <> text ">" -- closing- -- Horizontally aligned material that is vertically represented in source.- pp (HtmlSeq xs) = vert (map pp xs)- pp (Text str _) =- text (skipWs str) where- skipWs str = List.dropWhile Char.isSpace str- pp (Comment str _) =- text "<!--" <+> text str <+> text "-->"- pp (ProcessingInstruction str _) =- text "<?" <> text str <> text ">"- pp (Script script _) =- pp script- pp (InlineScript script _ "") =- text "{!" <+> pp script <+> text "!}"- pp (InlineScript script _ init) =- text "{!" <+> pp script <+> text "|||" <+> text init <+> text "!}"-
− src/WebBits/Html/RawScript.hs
@@ -1,34 +0,0 @@-module WebBits.Html.RawScript- ( RawScript (..)- , parseFromFile- , parseFromString- , RawHtml- ) where--import Data.Generics (Data)-import Data.Generics (Typeable)-import Text.PrettyPrint.HughesPJ (text)-import Text.ParserCombinators.Parsec-import WebBits.Common-import WebBits.Html.Html--type RawHtml = Html SourcePos RawScript--data RawScript = RawScript String deriving (Show,Eq,Typeable,Data)--instance Script RawScript where- parseInlineScript = Nothing- - parseAttributeScript = Nothing- - parseScriptBlock _ = do- s <- manyTill anyChar (string "</script>")- return (RawScript s)- -instance PrettyPrintable RawScript where- pp (RawScript s) = text s--parseFromString :: String -> RawHtml-parseFromString s = case parseHtmlFromString "" s of- Left e -> error (show e)- Right (html,_) -> html
− src/WebBits/Html/Syntax.hs
@@ -1,84 +0,0 @@--- |Datatypes for HTML parameterized over an annotation type and a script type. -module WebBits.Html.Syntax ( - -- * HTML Data Structures - HtmlId,AttributeValue,Attribute(..),Html(..) - -- * The Script class - , Script(..) - -- * Miscellaneous Functions - , attributeValue,attributeUpdate,attributeSet,isAttributeExpr - ) where - -import Text.ParserCombinators.Parsec(CharParser,SourcePos) -import Data.Generics(Data) -import Data.Typeable(Typeable) - --------------------------------------------------------------------------------- --- Types - -type HtmlId = String -type AttributeValue = String - -data Attribute a s - = Attribute HtmlId AttributeValue a - | AttributeExpr a HtmlId s String - deriving (Show,Eq,Typeable,Data) - -data Html a sc - = Element HtmlId [Attribute a sc] [Html a sc] a - | Text String a - | Comment String a - | HtmlSeq [Html a sc] -- ^must be a non-empty list - | ProcessingInstruction String a - | InlineScript sc a String - | Script sc a - deriving (Show,Eq,Typeable,Data) - --------------------------------------------------------------------------------- --- The Script class - --- |A type 't' of the 'Script' class can be parsed using 'Parsec'. 't' is of --- kind '* -> *', as the parsed AST should be annotated with souce locations --- (see 'Text.ParserCombinators.Parsec.SourcePos'). --- --- The big deal here is that we can embed a parser for some scripting language, --- (e.g. Javascript) into this HTML parser with ease, while preserving source --- locations. The Html datatype is parameterized over a script parser (an --- instance of Script). -class Script t where - parseScriptBlock:: [Attribute SourcePos t] -> CharParser a t - -- An inline script parser, which may be Nothing if the scripting language - -- does not support inline scripts. - parseInlineScript:: Maybe (CharParser a t) - -- A parser for script-expressions defined inline as attribute values. - parseAttributeScript:: Maybe (CharParser a t) - --------------------------------------------------------------------------------- --- HTML navigation - -isAttributeExpr (AttributeExpr _ _ _ _) = True -isAttributeExpr _ = False - --- |Returns the value of the attribute in the list, or 'Nothing' if it doesn't --- exist of the value is an inline-expression. -attributeValue:: HtmlId -> [Attribute a s] -> Maybe String -attributeValue name [] = Nothing -attributeValue name ((AttributeExpr pos name' expr init):rest) = - if name == name' then Nothing - else attributeValue name rest -attributeValue name ((Attribute name' value _):rest) = - if name == name' then Just value - else attributeValue name rest - -attributeSet:: HtmlId -> String -> [Attribute a s] -> [Attribute a s] -attributeSet n v attrs = attributeUpdate n (\_ -> v) attrs - -attributeUpdate:: HtmlId -> (String -> String) -> [Attribute a s] - -> [Attribute a s] -attributeUpdate n f [] = - [Attribute n (f "") (error "attributeUpdate--no value")] -- TODO: undefined?! -attributeUpdate n _ ((AttributeExpr _ _ _ _):_) = - error $ "attributeUpdate: " ++ n ++ " is an expression-attribute." -attributeUpdate n f ((Attribute n' v p):attrs) = - if n' == n then (Attribute n (f v) p):attrs - else (Attribute n' v p):(attributeUpdate n f attrs) -
− src/WebBits/JavaScript.hs
@@ -1,21 +0,0 @@--- |Re-exports commonly used modules.-module WebBits.JavaScript- ( module WebBits.JavaScript.Syntax- , module WebBits.JavaScript.HtmlEmbedding- , module WebBits.JavaScript.Parser- , module WebBits.JavaScript.Combinators- , module WebBits.Common- , module WebBits.JavaScript.Environment- -- JavaScript.Instances exports nothing- ) where--import WebBits.Common--import WebBits.JavaScript.Syntax-import WebBits.JavaScript.Parser-import WebBits.JavaScript.PrettyPrint-import WebBits.JavaScript.HtmlEmbedding-import WebBits.JavaScript.Combinators-import WebBits.JavaScript.Environment--import WebBits.JavaScript.Instances
− src/WebBits/JavaScript/Combinators.hs
@@ -1,39 +0,0 @@-module WebBits.JavaScript.Combinators - ( scriptStatements- , isParenExpr- , syntaxAt- , expressionsAt- , statementsAt- ) where--import Data.Generics (Data,Typeable, everything, mkQ)-import Text.ParserCombinators.Parsec (SourcePos)-import qualified Data.Foldable as F-import Data.Foldable (Foldable)-import WebBits.JavaScript.Syntax-import WebBits.JavaScript.Instances ()-import WebBits.Common () --scriptStatements:: JavaScript a -> [Statement a]-scriptStatements (Script _ ss) = ss--isParenExpr (ParenExpr _ _) = True-isParenExpr _ = False--syntaxAt :: (Data a, Typeable a, Data (t SourcePos), - Typeable (t SourcePos), Foldable t)- => SourcePos -> a -> [t SourcePos]-syntaxAt pos a = everything (++) (mkQ [] isMatch) a where- isMatch stx = case F.find (const True) stx of- Nothing -> []- Just pos' | pos == pos' -> [stx]- | otherwise -> []--expressionsAt :: (Data a, Typeable a) - => SourcePos -> a -> [Expression SourcePos]-expressionsAt = syntaxAt--statementsAt :: (Data a, Typeable a) - => SourcePos -> a -> [Statement SourcePos]-statementsAt = syntaxAt-
− src/WebBits/JavaScript/Crawl.hs
@@ -1,80 +0,0 @@--- |Crawls an HTML page for JavaScript-module WebBits.JavaScript.Crawl - ( getPageJavaScript- ) where--import WebBits.Common-import Control.Monad-import Data.Char (toLower)-import Data.Generics-import System.IO-import Text.ParserCombinators.Parsec(parse,setPosition,incSourceColumn,Column,sourceLine,sourceColumn)--import WebBits.Html.Syntax-import qualified WebBits.JavaScript.JavaScript as Js---- |Returns the source of the script.-scriptSrc:: Js.ParsedJsHtml -> [String]-scriptSrc (Element tag attrs _ _) | (map toLower tag) == "script" =- case attributeValue "src" attrs of -- TODO: Check for type="javascript"?- Just "" -> []- Just url -> [url]- Nothing -> []-scriptSrc _ =- []---- |Returns a list of URIs for external Javascript files referenced in the page.-importedScripts:: Js.ParsedJsHtml -> [String]-importedScripts = everything (++) (mkQ [] scriptSrc)---- |Returns the top-level statements of a script.-scriptText :: Js.ParsedJsHtml -> [Js.ParsedStatement]-scriptText (Script (Js.Script _ stmts) _) = stmts-scriptText _ = []--eventHandlers :: [String]-eventHandlers = ["onload","onclick"]; --- ,"onmousemove","onmouseover","onmousedown","onmouseout","onmouseup","onselectstart", "onkeypress"]--attrScript :: Attribute SourcePos Js.ParsedJavaScript - -> IO [Js.ParsedStatement]-attrScript (Attribute id val loc) | id `elem` eventHandlers = do- let eventId = drop 2 id -- drop the "on" prefix- let scriptText = if "javascript:" `isPrefixOf` val then drop 11 val else val- let eventListenerPrefix = "addEventListener('" ++ eventId ++ "', function(event) { "- let prefixLen = length eventListenerPrefix- let eventListenerText = eventListenerPrefix ++ scriptText ++ " });"- let parser = do- setPosition (incSourceColumn loc (-prefixLen))- Js.parseExpression- case parse parser (sourceName loc) eventListenerText of- Left err -> do- fail $ "Error parsiing JavaScript in an attribute at " ++ show loc ++- "\nThe script was:\n\n" ++ eventListenerText- Right e -> return [Js.ExprStmt loc e]-attrScript _ = return []--inpageAttrScripts :: Js.ParsedJsHtml -> IO [Js.ParsedStatement]-inpageAttrScripts = everything (liftM2 (++)) (mkQ (return []) attrScript)--inpageScripts :: Js.ParsedJsHtml -> [Js.ParsedStatement]-inpageScripts = everything (++) (mkQ [] scriptText)--parseJsFile path = do- text <- readFile path- case Js.parseScriptFromString path text of- Left err -> fail (show err)- Right js -> hPutStrLn stderr ("Read file " ++ path) >> return js---- |Given an HTML page, crawls all external Javascript files and returns a list--- of statements, concatenated from all files.-getPageJavascript:: Js.ParsedJsHtml -> IO [Js.ParsedStatement]-getPageJavascript page = do- let importURIs = importedScripts page- let inpageJs = inpageScripts page- attrScripts <- inpageAttrScripts page- importedScripts <- mapM parseJsFile importURIs- return $ (concatMap Js.scriptStatements importedScripts ++ attrScripts) ++ inpageJs--getPageJavaScript:: Js.ParsedJsHtml -> IO [Js.ParsedStatement] -- monomorphism-getPageJavaScript = getPageJavascript
− src/WebBits/JavaScript/Environment.hs
@@ -1,304 +0,0 @@-module WebBits.JavaScript.Environment - ( staticEnvironment- , Ann- , LabelledStatement- , LabelledExpression- , Env- ) where--import Data.Generics hiding (GT)-import Data.Maybe (fromJust)-import qualified Data.Set as S-import WebBits.Data.Zipper (ZipperT,ZipperT)-import qualified Data.Map as M-import qualified WebBits.Data.Zipper as Z-import Control.Monad.State-import qualified Data.Foldable as F-import qualified Data.List as L-import WebBits.JavaScript.JavaScript-import Text.ParserCombinators.Parsec.Pos (SourcePos,initialPos)-------- Add `this' and `arguments' to the formal parameters of all --- functions ------ TODO: Does a local var x shadow a formal argument x? What about 'arguments'?--thisStmt :: Statement SourcePos -> Statement SourcePos-thisStmt (FunctionStmt loc id args body) = - FunctionStmt loc id ((Id loc "this"):(Id loc "arguments"):args) body-thisStmt s = s--thisExpr :: Expression SourcePos -> Expression SourcePos-thisExpr (FuncExpr l args s) = - FuncExpr l ((Id l "this"):(Id l "arguments"):args) s-thisExpr e = e--removeParens :: Expression SourcePos -> Expression SourcePos-removeParens (ParenExpr _ e) = e-removeParens e = e--removeSingletons :: Expression SourcePos -> Expression SourcePos-removeSingletons (ListExpr _ [e]) = e-removeSingletons e = e--explicitThis :: [Statement SourcePos] -> [Statement SourcePos]-explicitThis = everywhere $ (mkT removeSingletons) . (mkT removeParens) - . (mkT thisExpr) . (mkT thisStmt)---- JavaScript has a global and function scopes. Globals do not need to be--- declared. Any "unbound identifier" in a function is treated as a reference--- to a global.---- For each FunctionExpr and FunctionStmt, we create a list of locally defined--- identifiers (var x = ...) and free identifiers.---- We build a tree of "partial environments." Since a variable may be used--- before it is declared locally, we maintain a set of free identifiers and--- narrow the set when appropriate.-type PartialEnv = (Env,S.Set String)--type Env = M.Map String Int--emptyPartialEnv :: PartialEnv-emptyPartialEnv = (M.empty,S.empty)--type RefM a = Z.ZipperT PartialEnv (State Int) a--nextLabel :: (MonadTrans t, Monad (t (State Int))) => t (State Int) Int-nextLabel = do- l <- lift get- lift $ modify (+1)- return l - -bind :: Id SourcePos -> RefM ()-bind (Id _ s) = do- lbl <- nextLabel- (env,freeIds) <- Z.getNode- Z.setNode (M.insert s lbl env, S.delete s freeIds)- -use :: Id SourcePos -> RefM ()-use (Id _ s) = do- (env,freeIds) <- Z.getNode- case M.lookup s env of- Just _ -> return ()- Nothing -> Z.setNode (env, S.insert s freeIds)- --buildExpr :: Expression SourcePos -> RefM (Expression SourcePos)-buildExpr (FuncExpr loc args stmt) = do- stmt' <- Z.nest emptyPartialEnv (mapM_ bind args >> buildStmt stmt)- return (FuncExpr loc args stmt')-buildExpr e@(VarRef _ id) = do- use id- return e-buildExpr (AssignExpr loc op (VarRef loc' id) e) = do- use id- e' <- buildExpr e- return (AssignExpr loc op (VarRef loc' id) e')-buildExpr e =- gmapM buildAny e--buildCatchClause :: CatchClause SourcePos -> RefM (CatchClause SourcePos)-buildCatchClause (CatchClause loc id stmt) = do- bind id- stmt' <- buildStmt stmt- return (CatchClause loc id stmt')- -buildVarDecl :: VarDecl SourcePos -> RefM (VarDecl SourcePos)-buildVarDecl (VarDecl loc id ye) = do- bind id- ye' <- gmapM buildAny ye- return (VarDecl loc id ye')--buildForInInit :: ForInInit SourcePos -> RefM (ForInInit SourcePos)-buildForInInit e@(ForInVar id) = do- bind id- return e-buildForInInit e@(ForInNoVar id) = do- use id- return e- -buildStmt :: Statement SourcePos -> RefM (Statement SourcePos)-buildStmt (FunctionStmt loc id args stmt) = do- stmt' <- Z.nest emptyPartialEnv (mapM_ bind args >> buildStmt stmt)- return (FunctionStmt loc id args stmt')-buildStmt s = gmapM buildAny s--buildAny' :: (Data a, Typeable a) => a -> RefM a-buildAny' v = gmapM buildAny v--buildAny :: GenericM RefM-buildAny =- buildAny' `extM` buildExpr `extM` buildCatchClause `extM`- buildVarDecl `extM` buildForInInit `extM` buildStmt------- buildAny creates a tree of partial environments. We now walk the tree and--- attempt to associate free identifiers with their bindings in enclosing--- scopes. Any remaining free identifiers are globals.-----resolveFreeId :: Env -> String -> StateT Env (State Int) Env-resolveFreeId env freeId = case M.lookup freeId env of- Just lbl -> return env -- the free identifier was bound in an enclosing env- Nothing -> do -- this is a global - globals <- get- case M.lookup freeId globals of- Just lbl -> return (M.insert freeId lbl env) -- global already bound- Nothing -> do -- new global- lbl <- nextLabel- put (M.insert freeId lbl globals)- return (M.insert freeId lbl env)---completeEnvM' :: Z.Tree PartialEnv -> StateT Env (State Int) (Z.Tree Env)-completeEnvM' pt = Z.dfsFoldM f M.empty pt where- -- the union is left-biased; bindings in env shadow bindings in enclosingEnv- f enclosingEnv (env,freeIds) = - foldM resolveFreeId (M.union env enclosingEnv) (S.elems freeIds) --completeEnvM :: Z.Tree PartialEnv -> StateT Env (State Int) (Z.Tree Env)-completeEnvM pt = do- tree <- completeEnvM' pt- globals <- get- -- left-biased union: lexicals shadow globals- return (fmap (\lexicals -> M.union lexicals globals) tree)------- completeEnvM creates a tree of environments whose structure is identical to--- the function-nesting structure of the JavaScript source. We walk the tree--- and the code in step and annotate the code with environments.-----type Ann = (Env,Int,SourcePos)--type LabelledStatement = Statement Ann-type LabelledExpression = Expression Ann---- Necessary for type-checking. gmapM won't let us transform the type of the--- annotation. So, we first inject SourcePos into a trivial Ann.-insertEmptyAnn :: (Functor f) => f SourcePos -> f Ann-insertEmptyAnn = fmap (\loc -> (M.empty,0,loc))---locOf :: F.Foldable t => t SourcePos -> SourcePos-locOf = fromJust . (F.find $ const True)--labelEnv :: Env -> Z.ZipperT Env (State Int) Env-labelEnv env = Z.getNode--labelId :: Id Ann -> Z.ZipperT Env (State Int) (Id Ann)-labelId id@(Id (_,_,loc) s) = do- env <- Z.getNode- case M.lookup s env of- Nothing -> fail $ "BUG: unbound identifier while labelling" ++ show id- Just lbl -> return (Id (env,lbl,loc) s)- -labelIdNoVar :: Id Ann -> Z.ZipperT Env (State Int) (Id Ann)-labelIdNoVar (Id (_,_,loc) s) = do- env <- Z.getNode- lbl <- nextLabel- return (Id (env,lbl,loc) s)--labelProp :: Prop Ann -> Z.ZipperT Env (State Int) (Prop Ann)-labelProp (PropId (_,_,loc) id) = do- env <- Z.getNode- lbl <- nextLabel- id' <- labelIdNoVar id- return (PropId (env,lbl,loc) id')-labelProp e = gmapM labelAny e---labelVarDecl :: VarDecl Ann- -> Z.ZipperT Env (State Int) (VarDecl Ann)-labelVarDecl (VarDecl (_,_,loc) id@(Id _ name) rhs) = do- env <- Z.getNode- case M.lookup name env of- Nothing -> fail $ "WebBits bug: unbound id in labelVarDecl (" ++ name ++ ")"- Just lbl' -> case rhs of- Nothing -> return (VarDecl (env,lbl',loc) id Nothing)- Just expr -> do- expr' <- labelExpr expr- return (VarDecl (env,lbl',loc) id (Just expr'))--labelExpr :: Expression Ann - -> Z.ZipperT Env (State Int) (Expression Ann)-labelExpr (ThisRef (_,_,loc)) = do- env <- Z.getNode- case M.lookup "this" env of- Just lbl -> return $ ThisRef (env,lbl,loc)- Nothing -> fail "BUG: expected to find this in the environment"-labelExpr (DotRef (_,_,loc) expr id) = do- env <- Z.getNode- lbl <- nextLabel- id' <- labelIdNoVar id- expr' <- labelExpr expr- return (DotRef (env,lbl,loc) expr' id')-labelExpr (VarRef (_,_,loc) id@(Id _ name)) = do- env <- Z.getNode- case M.lookup name env of- Nothing -> fail $ "WebBits bug : unbound identifer " ++ name- Just lbl' -> return (VarRef (env,lbl',loc) id)-labelExpr (FuncExpr (_,_,loc) args stmt) = do- env <- Z.getNode- lbl <- nextLabel- args' <- Z.withCurrentChild (mapM labelId args)- stmt' <- Z.withCurrentChild (labelStmt stmt)- Z.shiftRight'- return (FuncExpr (env,lbl,loc) args' stmt')-labelExpr e = gmapM labelAny e- -labelStmt :: Statement Ann- -> Z.ZipperT Env (State Int) (Statement Ann)-labelStmt (BreakStmt (_,_,loc) (Just id)) = do- env <- Z.getNode- lbl <- nextLabel- id' <- labelIdNoVar id- return (BreakStmt (env,lbl,loc) (Just id'))-labelStmt (ContinueStmt (_,_,loc) (Just id)) = do- env <- Z.getNode- lbl <- nextLabel- id' <- labelIdNoVar id- return (ContinueStmt (env,lbl,loc) (Just id'))-labelStmt (LabelledStmt (_,_,loc) id stmt) = do- env <- Z.getNode- lbl <- nextLabel- id' <- labelIdNoVar id- stmt' <- labelStmt stmt- return (LabelledStmt (env,lbl,loc) id' stmt') -labelStmt (FunctionStmt (_,_,loc) id args stmt) = do- env <- Z.getNode- lbl <- nextLabel- args' <- Z.withCurrentChild (mapM labelId args)- stmt' <- Z.withCurrentChild (labelStmt stmt)- Z.shiftRight'- return (FunctionStmt (env,lbl,loc) id args' stmt')-labelStmt e = gmapM labelAny e--labelAny' :: (Data a, Typeable a) => a -> Z.ZipperT Env (State Int) a-labelAny' a = gmapM labelAny a--labelAny :: GenericM (Z.ZipperT Env (State Int)) -labelAny a = (labelAny' `extM` labelEnv `extM` labelId `extM` labelProp `extM`- labelExpr `extM` labelStmt `extM` labelVarDecl) a--topLevelPartialEnv = (M.empty,S.singleton "this")---- |Annotates each expression with its static environment. In addition,--- a map of free identifiers is returned, along with the next valid label.-staticEnvironment :: [Statement SourcePos] - -> ([Statement Ann],Env,Env,Int)-staticEnvironment stmts =- let stmts' = explicitThis stmts- labelM = do- partialEnvTree <- Z.execZipperT (mapM buildStmt stmts')- (Z.toLocation (Z.Node topLevelPartialEnv []))- (envTree,freeEnv) <- runStateT (completeEnvM partialEnvTree) M.empty- let globals = M.union freeEnv (Z.rootLabel envTree)- let stmts'' = map insertEmptyAnn stmts' - labelledStmts <- Z.evalZipperT (mapM labelStmt stmts'') - (Z.toLocation envTree)- return (labelledStmts,freeEnv,globals)- ((labelledStmts,freeEnv,globals),nextLabel) = runState labelM 1- in (labelledStmts,freeEnv,globals,nextLabel)
− src/WebBits/JavaScript/HtmlEmbedding.hs
@@ -1,26 +0,0 @@-module WebBits.JavaScript.HtmlEmbedding- ( JsHtml- , ParsedJavaScript- , ParsedJsHtml- ) where--import WebBits.Html.Syntax(Html,Script,parseScriptBlock,parseInlineScript,- parseAttributeScript)-import WebBits.JavaScript.Parser(parseScript)-import WebBits.JavaScript.Syntax(JavaScript)---import JavaScript.PrettyPrint -- for the instance declaration-import Text.ParserCombinators.Parsec (SourcePos)--type JsHtml a = Html SourcePos (JavaScript a)--type ParsedJavaScript = JavaScript SourcePos--type ParsedJsHtml = JsHtml SourcePos--instance Script ParsedJavaScript where- parseScriptBlock attrs = do- parseScript- parseInlineScript = Nothing- parseAttributeScript = Nothing- -
− src/WebBits/JavaScript/Instances.hs
@@ -1,291 +0,0 @@--- |Instances of 'Foldable' and 'Traversable' for JavaScript's syntax.-module WebBits.JavaScript.Instances- ( -- This module does not export any names.- ) where--import Prelude hiding (foldr,sequence,mapM)-import qualified Prelude as Prelude--import Data.Foldable (Foldable(..))-import Data.Traversable(Traversable(..))-import Control.Applicative--import WebBits.JavaScript.Syntax--yfoldr:: Foldable t => (a -> b -> b) -> b -> Maybe (t a) -> b-yfoldr _ b Nothing = b-yfoldr f b (Just t) = foldr f b t--lfoldr:: Foldable t => (a -> b -> b) -> b -> [t a] -> b-lfoldr f = Prelude.foldr (flip $ foldr f)--ltraverse:: (Traversable t, Applicative f) => (a -> f b) -> [t a] -> f [t b]-ltraverse _ [] = pure []-ltraverse f (a:as) = (:) <$> traverse f a <*> ltraverse f as--ytraverse:: (Traversable t, Applicative f) - => (a -> f b) -> Maybe (t a) -> f (Maybe (t b))-ytraverse _ Nothing = pure Nothing-ytraverse f (Just t) = Just <$> traverse f t--instance Functor Id where- fmap f (Id a v) = Id (f a) v--instance Functor JavaScript where- fmap f (Script a stmts) = Script (f a) (map (fmap f) stmts)- -instance Functor Prop where- fmap f (PropId a id) = PropId (f a) (fmap f id)- fmap f (PropString a s) = PropString (f a) s- fmap f (PropNum a n) = PropNum (f a) n--instance Functor Expression where- fmap f expression = - case expression of- StringLit a s -> StringLit (f a) s- RegexpLit a s g ci -> RegexpLit (f a) s g ci- NumLit a n -> NumLit (f a) n- BoolLit a b -> BoolLit (f a) b- NullLit a -> NullLit (f a)- ArrayLit a es -> ArrayLit (f a) (map (fmap f) es)- ObjectLit a pes -> ObjectLit (f a) (map f' pes) where- f' (p,e) = (fmap f p, fmap f e)- ThisRef a -> ThisRef (f a)- VarRef a id -> VarRef (f a) (fmap f id)- DotRef a e id -> DotRef (f a) (fmap f e) (fmap f id)- BracketRef a e1 e2 -> BracketRef (f a) (fmap f e1) (fmap f e2)- NewExpr a e es -> NewExpr (f a) (fmap f e) (map (fmap f) es)- PostfixExpr a op e -> PostfixExpr (f a) op (fmap f e)- PrefixExpr a op e -> PrefixExpr (f a) op (fmap f e)- InfixExpr a op e1 e2 -> InfixExpr (f a) op (fmap f e1) (fmap f e2)- CondExpr a e1 e2 e3 -> CondExpr (f a) (fmap f e1) (fmap f e2) (fmap f e3)- AssignExpr a op e1 e2 -> AssignExpr (f a) op (fmap f e1) (fmap f e2)- ParenExpr a e -> ParenExpr (f a) (fmap f e)- ListExpr a es -> ListExpr (f a) (map (fmap f) es)- CallExpr a e es -> CallExpr (f a) (fmap f e) (map (fmap f) es)- FuncExpr a args s -> FuncExpr (f a) (map (fmap f) args) (fmap f s)--instance Functor CaseClause where- fmap f (CaseClause a e ss) = CaseClause (f a) (fmap f e) (map (fmap f) ss)- fmap f (CaseDefault a ss) = CaseDefault (f a) (map (fmap f) ss)- -instance Functor CatchClause where- fmap f (CatchClause a id s) = CatchClause (f a) (fmap f id) (fmap f s)--instance Functor VarDecl where- fmap f (VarDecl a id Nothing) = VarDecl (f a) (fmap f id) Nothing- fmap f (VarDecl a id (Just e)) = VarDecl (f a) (fmap f id) (Just $ fmap f e)- -instance Functor ForInit where- fmap f NoInit = NoInit- fmap f (VarInit decls) = VarInit (map (fmap f) decls)- fmap f (ExprInit e) = ExprInit (fmap f e)--instance Functor ForInInit where- fmap f (ForInVar id) = ForInVar (fmap f id)- fmap f (ForInNoVar id) = ForInNoVar (fmap f id)- -instance Functor Statement where- fmap f s = - case s of- BlockStmt a ss -> BlockStmt (f a) (map (fmap f) ss)- EmptyStmt a -> EmptyStmt (f a)- ExprStmt a e -> ExprStmt (f a) (fmap f e)- IfStmt a e s1 s2 -> IfStmt (f a) (fmap f e) (fmap f s1) (fmap f s2)- IfSingleStmt a e s -> IfSingleStmt (f a) (fmap f e) (fmap f s)- SwitchStmt a e cs -> SwitchStmt (f a) (fmap f e) (map (fmap f) cs)- WhileStmt a e s -> WhileStmt (f a) (fmap f e) (fmap f s)- DoWhileStmt a s e -> DoWhileStmt (f a) (fmap f s) (fmap f e)- BreakStmt a Nothing -> BreakStmt (f a) Nothing- BreakStmt a (Just id) -> BreakStmt (f a) (Just (fmap f id))- ContinueStmt a yid -> ContinueStmt (f a) (yid >>= return.(fmap f))- LabelledStmt a id s -> LabelledStmt (f a) (fmap f id) (fmap f s)- ForInStmt a init e s -> ForInStmt (f a) (fmap f init) (fmap f e)- (fmap f s)- ForStmt a init yinc ytest body -> - ForStmt (f a) (fmap f init) (yinc >>= return.(fmap f))- (ytest >>= return.(fmap f)) (fmap f body)- TryStmt a s cs ys -> - TryStmt (f a) (fmap f s) (map (fmap f) cs) (ys >>= return.(fmap f))- ThrowStmt a e -> ThrowStmt (f a) (fmap f e)- ReturnStmt a ye -> ReturnStmt (f a) (ye >>= return.(fmap f))- WithStmt a e s -> WithStmt (f a) (fmap f e) (fmap f s)- VarDeclStmt a ds -> VarDeclStmt (f a) (map (fmap f) ds)- FunctionStmt a id args s -> - FunctionStmt (f a) (fmap f id) (map (fmap f) args) (fmap f s)--instance Foldable Id where- foldr f b (Id a _) = f a b--instance Foldable Prop where- foldr f b (PropId a id) = f a (foldr f b id)- foldr f b (PropString a _) = f a b- foldr f b (PropNum a _) = f a b- -instance Foldable Expression where- -- foldr:: (a -> b -> b) -> b -> Expression a -> b- foldr f b e =- case e of- StringLit a _ -> f a b- RegexpLit a _ _ _ -> f a b- NumLit a _ -> f a b- BoolLit a _ -> f a b- NullLit a -> f a b- ArrayLit a es -> f a (Prelude.foldr (flip $ foldr f) b es)- ObjectLit a pes -> f a (Prelude.foldr f' b pes) where- f' (p,e) b = foldr f (foldr f b e) p- ThisRef a -> f a b- VarRef a id -> f a (foldr f b id)- DotRef a e id -> f a (foldr f (foldr f b id) e)- BracketRef a e1 e2 -> f a (foldr f (foldr f b e2) e1)- NewExpr a e es -> f a (foldr f (Prelude.foldr (flip $ foldr f) b es) e)- PostfixExpr a _ e -> f a $ foldr f b e- PrefixExpr a _ e -> f a $ foldr f b e- InfixExpr a _ e1 e2 -> f a $ foldr f (foldr f b e2) e1- CondExpr a e1 e2 e3 -> f a $ foldr f (foldr f (foldr f b e3) e2) e1- AssignExpr a _ e1 e2 -> f a $ foldr f (foldr f b e2) e1- ParenExpr a e -> f a $ foldr f b e- ListExpr a es -> f a $ Prelude.foldr (flip $ foldr f) b es- CallExpr a e es -> f a $ foldr f (Prelude.foldr (flip $ foldr f) b es) e- FuncExpr a args s -> - f a $ Prelude.foldr (flip $ foldr f) (foldr f b s) args--instance Foldable CaseClause where- foldr f b (CaseClause a e ss) = - f a $ foldr f (Prelude.foldr (flip $ foldr f) b ss) e- foldr f b (CaseDefault a ss) = f a $ Prelude.foldr (flip $ foldr f) b ss- -instance Foldable CatchClause where- foldr f b (CatchClause a id s) = f a $ foldr f (foldr f b s) id--instance Foldable VarDecl where- foldr f b (VarDecl a id ye) = f a $ foldr f (yfoldr f b ye) id--instance Foldable ForInit where- foldr f b NoInit = b- foldr f b (VarInit ds) = Prelude.foldr (flip $ foldr f) b ds- foldr f b (ExprInit e) = foldr f b e--instance Foldable ForInInit where- foldr f b (ForInVar id) = foldr f b id- foldr f b (ForInNoVar id) = foldr f b id--instance Foldable Statement where- foldr f b statement =- case statement of- BlockStmt a ss -> f a $ lfoldr f b ss- EmptyStmt a -> f a b- ExprStmt a e -> f a $ foldr f b e- IfStmt a e s1 s2 -> f a $ foldr f (foldr f (foldr f b s2) s1) e- IfSingleStmt a e s -> f a $ foldr f (foldr f b s) e- SwitchStmt a e cs -> f a $ foldr f (lfoldr f b cs) e- WhileStmt a e s -> f a $ foldr f (foldr f b s) e- DoWhileStmt a s e -> f a $ foldr f (foldr f b e) s- BreakStmt a yid -> f a $ yfoldr f b yid- ContinueStmt a yid -> f a $ yfoldr f b yid- LabelledStmt a id s -> f a $ foldr f (foldr f b s) id- ForInStmt a init e s -> f a $ foldr f (foldr f (foldr f b s) e) init- ForStmt a init ye1 ye2 s ->- f a $ foldr f (yfoldr f (yfoldr f (foldr f b s) ye2) ye1) init- TryStmt a s cs ys -> f a $ foldr f (lfoldr f (yfoldr f b ys) cs) s- ThrowStmt a e -> f a $ foldr f b e- ReturnStmt a ys -> f a $ yfoldr f b ys- WithStmt a e s -> f a $ foldr f (foldr f b s) e- VarDeclStmt a ds -> f a $ lfoldr f b ds- FunctionStmt a id args s ->- f a $ lfoldr f (foldr f b s) (id:args)--instance Traversable Id where- traverse f (Id a v) = Id <$> f a <*> pure v--instance Traversable Prop where- traverse f (PropId a id) = PropId <$> f a <*> traverse f id- traverse f (PropString a s) = PropString <$> f a <*> pure s- traverse f (PropNum a n) = PropNum <$> f a <*> pure n- -instance Traversable Expression where- traverse f expression =- case expression of- StringLit a s -> StringLit <$> f a <*> pure s- RegexpLit a s g ci -> RegexpLit <$> f a <*> pure s <*> pure g <*> pure ci- NumLit a n -> NumLit <$> f a <*> pure n- BoolLit a b -> BoolLit <$> f a <*> pure b- NullLit a -> NullLit <$> f a- ArrayLit a es -> ArrayLit <$> f a <*> ltraverse f es- ObjectLit a ps -> ObjectLit <$> f a <*> (zip <$> props' <*> es') where- (props,es) = unzip ps- props' = ltraverse f props- es' = ltraverse f es- ThisRef a -> ThisRef <$> f a- VarRef a id -> VarRef <$> f a <*> traverse f id- DotRef a e id -> DotRef <$> f a <*> traverse f e <*> traverse f id- BracketRef a e es -> BracketRef <$> f a <*> traverse f e <*> traverse f es- NewExpr a e es -> NewExpr <$> f a <*> traverse f e <*> ltraverse f es- PostfixExpr a op e -> PostfixExpr <$> f a <*> pure op <*> traverse f e- PrefixExpr a op e -> PrefixExpr <$> f a <*> pure op <*> traverse f e- InfixExpr a op e1 e2 -> InfixExpr <$> f a <*> pure op <*> traverse f e1- <*> traverse f e2- CondExpr a e1 e2 e3 ->- CondExpr <$> f a <*> traverse f e1 <*> traverse f e2 <*> traverse f e3- AssignExpr a op e1 e2 -> AssignExpr <$> f a <*> pure op <*> traverse f e1- <*> traverse f e2- ParenExpr a e -> ParenExpr <$> f a <*> traverse f e- ListExpr a es -> ListExpr <$> f a <*> ltraverse f es- CallExpr a e es -> CallExpr <$> f a <*> traverse f e <*> ltraverse f es- FuncExpr a ids s -> FuncExpr <$> f a <*> ltraverse f ids <*> traverse f s--instance Traversable CaseClause where- traverse f (CaseClause a e ss) =- CaseClause <$> f a <*> traverse f e <*> ltraverse f ss- traverse f (CaseDefault a ss) = - CaseDefault <$> f a <*> ltraverse f ss--instance Traversable CatchClause where- traverse f (CatchClause a id s) = - CatchClause <$> f a <*> traverse f id <*> traverse f s- -instance Traversable VarDecl where- traverse f (VarDecl a id ye) =- VarDecl <$> f a <*> traverse f id <*> ytraverse f ye--instance Traversable ForInit where- traverse f NoInit = pure NoInit- traverse f (VarInit ds) = VarInit <$> ltraverse f ds- traverse f (ExprInit e) = ExprInit <$> traverse f e--instance Traversable ForInInit where- traverse f (ForInVar id) = ForInVar <$> traverse f id- traverse f (ForInNoVar id) = ForInNoVar <$> traverse f id--instance Traversable Statement where- traverse f statement =- case statement of- BlockStmt a ss -> BlockStmt <$> f a <*> ltraverse f ss- EmptyStmt a -> EmptyStmt <$> f a- ExprStmt a e -> ExprStmt <$> f a <*> traverse f e- IfStmt a e s1 s2 ->- IfStmt <$> f a <*> traverse f e <*> traverse f s1 <*> traverse f s2- IfSingleStmt a e s ->- IfSingleStmt <$> f a <*> traverse f e <*> traverse f s- SwitchStmt a e cs ->- SwitchStmt <$> f a <*> traverse f e <*> ltraverse f cs- WhileStmt a e s -> WhileStmt <$> f a <*> traverse f e <*> traverse f s- DoWhileStmt a s e -> DoWhileStmt <$> f a <*> traverse f s <*> traverse f e- BreakStmt a yid -> BreakStmt <$> f a <*> ytraverse f yid- ContinueStmt a yid -> ContinueStmt <$> f a <*> ytraverse f yid- LabelledStmt a id s -> - LabelledStmt <$> f a <*> traverse f id <*> traverse f s- ForInStmt a init e s ->- ForInStmt <$> f a <*> traverse f init <*> traverse f e <*> traverse f s- ForStmt a init yinc ytest s ->- ForStmt <$> f a <*> traverse f init <*> ytraverse f yinc - <*> ytraverse f ytest <*> traverse f s- TryStmt a s cs ys ->- TryStmt <$> f a <*> traverse f s <*> ltraverse f cs <*> ytraverse f ys- ThrowStmt a e -> ThrowStmt <$> f a <*> traverse f e- ReturnStmt a ys -> ReturnStmt <$> f a <*> ytraverse f ys- WithStmt a e s -> WithStmt <$> f a <*> traverse f e <*> traverse f s- VarDeclStmt a ds -> VarDeclStmt <$> f a <*> ltraverse f ds- FunctionStmt a id args s ->- FunctionStmt <$> f a <*> traverse f id <*> ltraverse f args - <*> traverse f s
− src/WebBits/JavaScript/JavaScript.hs
@@ -1,19 +0,0 @@--- |Re-exports commonly used modules.-module WebBits.JavaScript.JavaScript- ( module WebBits.JavaScript.Syntax- , module WebBits.JavaScript.HtmlEmbedding- , module WebBits.JavaScript.Parser- , module WebBits.JavaScript.Combinators- , module WebBits.Common- -- JavaScript.Instances exports nothing- ) where--import WebBits.Common--import WebBits.JavaScript.Syntax-import WebBits.JavaScript.Parser-import WebBits.JavaScript.PrettyPrint-import WebBits.JavaScript.HtmlEmbedding-import WebBits.JavaScript.Combinators--import WebBits.JavaScript.Instances
− src/WebBits/JavaScript/Lexer.hs
@@ -1,64 +0,0 @@-{- This isn't a lexer in the sense that it provides a JavaScript token-stream. - - This module provides character-parsers for various JavaScript tokens. - -} -module WebBits.JavaScript.Lexer(lexeme,identifier,reserved,operator,reservedOp,charLiteral, - stringLiteral,natural,integer,float,naturalOrFloat, - decimal,hexadecimal,octal,symbol,whiteSpace,parens, - braces,brackets,squares,semi,comma,colon,dot, - identifierStart) where - -import Prelude hiding (lex) -import Text.ParserCombinators.Parsec -import qualified Text.ParserCombinators.Parsec.Token as T - -identifierStart = (letter <|> oneOf "$_") - -javascriptDef = - T.LanguageDef "/*" - "*/" - "//" - False -- no nested comments - {- Adapted from syntax/regexps.ss in Dave's code. -} - identifierStart - (alphaNum <|> oneOf "$_") -- identifier rest - (oneOf "{}<>()~.,?:|&^=!+-*/%!") -- operator start - (oneOf "=<>|&+") -- operator rest - ["break", "case", "catch", "const", "continue", "debugger", - "default", "delete", "do", "else", "enum", "false", "finally", - "for", "function", "if", "instanceof", "in", "let", "new", - "null", "return", "switch", "this", "throw", "true", "try", - "typeof", "var", "void", "while", "with"] - ["|=", "^=", "&=", "<<=", ">>=", ">>>=", "+=", "-=", "*=", "/=", - "%=", "=", ";", ",", "?", ":", "||", "&&", "|", "^", "&", - "===", "==", "=", "!==", "!=", "<<", "<=", "<", ">>>", ">>", - ">=", ">", "++", "--", "+", "-", "*", "/", "%", "!", "~", ".", - "[", "]", "{", "}", "(", ")","</","instanceof"] - True -- case-sensitive - -lex = T.makeTokenParser javascriptDef - --- everything but commaSep and semiSep -identifier = T.identifier lex -reserved = T.reserved lex -operator = T.operator lex -reservedOp = T.reservedOp lex -charLiteral = T.charLiteral lex -stringLiteral = T.stringLiteral lex -natural = T.natural lex -integer = T.integer lex -float = T.float lex -naturalOrFloat = T.naturalOrFloat lex -decimal = T.decimal lex -hexadecimal = T.hexadecimal lex -octal = T.octal lex -symbol = T.symbol lex -whiteSpace = T.whiteSpace lex -parens = T.parens lex -braces = T.braces lex -squares = T.squares lex -semi = T.semi lex -comma = T.comma lex -colon = T.colon lex -dot = T.dot lex -brackets = T.brackets lex -lexeme = T.lexeme lex
− src/WebBits/JavaScript/Parser.hs
@@ -1,657 +0,0 @@-module WebBits.JavaScript.Parser(parseScript,parseExpression - , parseString - , parseScriptFromString - , emptyParsedJavaScript - , ParsedStatement - , ParsedExpression - , parseJavaScriptFromFile - , parseSimpleExpr' - , parseBlockStmt - , parseStatement - , StatementParser - , ExpressionParser - , parseAssignExpr - ) where - -import WebBits.JavaScript.Lexer hiding (identifier) -import qualified WebBits.JavaScript.Lexer as Lexer -import WebBits.JavaScript.Syntax -import Text.ParserCombinators.Parsec -import Text.ParserCombinators.Parsec.Expr -import Control.Monad(liftM,liftM2) -import Control.Monad.Trans (MonadIO,liftIO) -import Numeric(readDec,readOct,readHex) -import Data.Char(chr) -import Data.Char - --- We parameterize the parse tree over source-locations. -type ParsedStatement = Statement SourcePos -type ParsedExpression = Expression SourcePos - - --- These parsers can store some arbitrary state -type StatementParser state = CharParser state ParsedStatement -type ExpressionParser state = CharParser state ParsedExpression - -identifier = - liftM2 Id getPosition Lexer.identifier - ---{{{ Statements - --- Keep in mind that Token.reserved parsers (exported from the lexer) do not --- consume any input on failure. Note that all statements (expect for labelled --- and expression statements) begin with a reserved-word. If we fail to parse --- this reserved-word, no input is consumed. Hence, we can have the massive or --- block that is parseExpression. Note that if the reserved-word is parsed, it --- must be whatever statement the reserved-word indicates. If we fail after the --- reserved-word, we truly have a syntax error. Since input has been consumed, --- <|> will not try its alternate in parseExpression, and we will fail. - -parseIfStmt:: StatementParser st -parseIfStmt = do - pos <- getPosition - reserved "if" - test <- parseParenExpr <?> "parenthesized test-expression in if statement" - consequent <- parseStatement <?> "true-branch of if statement" - optional semi -- TODO: in spec? - ((do reserved "else" - alternate <- parseStatement - return (IfStmt pos test consequent alternate)) - <|> return (IfSingleStmt pos test consequent)) - -parseSwitchStmt:: StatementParser st -parseSwitchStmt = - let parseDefault = do - pos <- getPosition - reserved "default" - colon - statements <- many parseStatement - return (CaseDefault pos statements) - parseCase = do - pos <- getPosition - reserved "case" - condition <- parseListExpr - colon - actions <- many parseStatement - return (CaseClause pos condition actions) - in do pos <- getPosition - reserved "switch" - test <- parseParenExpr - clauses <- braces $ many $ parseDefault <|> parseCase - return (SwitchStmt pos test clauses) - -parseWhileStmt:: StatementParser st -parseWhileStmt = do - pos <- getPosition - reserved "while" - test <- parseParenExpr <?> "parenthesized test-expression in while loop" - body <- parseStatement - return (WhileStmt pos test body) - -parseDoWhileStmt:: StatementParser st -parseDoWhileStmt = do - pos <- getPosition - reserved "do" - body <- parseBlockStmt - reserved "while" <?> "while at the end of a do block" - test <- parseParenExpr <?> "parenthesized test-expression in do loop" - optional semi - return (DoWhileStmt pos body test) - -parseContinueStmt:: StatementParser st -parseContinueStmt = do - pos <- getPosition - reserved "continue" - pos' <- getPosition - -- Ensure that the identifier is on the same line as 'continue.' - id <- (if (sourceLine pos == sourceLine pos') - then (liftM Just identifier) <|> (return Nothing) - else return Nothing) - return (ContinueStmt pos id) - -parseBreakStmt:: StatementParser st -parseBreakStmt = do - pos <- getPosition - reserved "break" - pos' <- getPosition - -- Ensure that the identifier is on the same line as 'break.' - id <- (if (sourceLine pos == sourceLine pos') - then (liftM Just identifier) <|> (return Nothing) - else return Nothing) - optional semi - return (BreakStmt pos id) - -parseBlockStmt:: StatementParser st -parseBlockStmt = do - pos <- getPosition - statements <- braces (many parseStatement) - return (BlockStmt pos statements) - -parseEmptyStmt:: StatementParser st -parseEmptyStmt = do - pos <- getPosition - semi - return (EmptyStmt pos) - -parseLabelledStmt:: StatementParser st -parseLabelledStmt = do - pos <- getPosition - -- Lookahead for the colon. If we don't see it, we are parsing an identifier - -- for an expression statement. - label <- try (do label <- identifier - colon - return label) - statement <- parseStatement - return (LabelledStmt pos label statement) - -parseExpressionStmt:: StatementParser st -parseExpressionStmt = do - pos <- getPosition - expr <- parseListExpr -- TODO: spec 12.4? - optional semi - return (ExprStmt pos expr) - - -parseForInStmt:: StatementParser st -parseForInStmt = - let parseInit = (reserved "var" >> liftM ForInVar identifier) - <|> (liftM ForInNoVar identifier) - in do pos <- getPosition - -- Lookahead, so that we don't clash with parseForStmt - (init,expr) <- try (do reserved "for" - parens (do init <- parseInit - reserved "in" - expr <- parseExpression - return (init,expr))) - body <- parseStatement - return (ForInStmt pos init expr body) - -parseForStmt:: StatementParser st -parseForStmt = - let parseInit = - (reserved "var" >> liftM VarInit (parseVarDecl `sepBy` comma)) <|> - (liftM ExprInit parseListExpr) <|> - (return NoInit) - in do pos <- getPosition - reserved "for" - reservedOp "(" - init <- parseInit - semi - test <- (liftM Just parseExpression) <|> (return Nothing) - semi - iter <- (liftM Just parseExpression) <|> (return Nothing) - reservedOp ")" <?> "closing paren" - stmt <- parseStatement - return (ForStmt pos init test iter stmt) - -parseTryStmt:: StatementParser st -parseTryStmt = - let parseCatchClause = do - pos <- getPosition - reserved "catch" - id <- parens identifier - stmt <- parseStatement - return (CatchClause pos id stmt) - in do reserved "try" - pos <- getPosition - guarded <- parseStatement - catches <- many parseCatchClause - finally <- (reserved "finally" >> liftM Just parseStatement) - <|> (return Nothing) - return (TryStmt pos guarded catches finally) - -parseThrowStmt:: StatementParser st -parseThrowStmt = do - pos <- getPosition - reserved "throw" - expr <- parseExpression - optional semi - return (ThrowStmt pos expr) - -parseReturnStmt:: StatementParser st -parseReturnStmt = do - pos <- getPosition - reserved "return" - expr <- (liftM Just parseListExpr) <|> (return Nothing) - optional semi - return (ReturnStmt pos expr) - -parseWithStmt:: StatementParser st -parseWithStmt = do - pos <- getPosition - reserved "with" - context <- parseParenExpr - stmt <- parseStatement - return (WithStmt pos context stmt) - -parseVarDecl = do - pos <- getPosition - id <- identifier - init <- (reservedOp "=" >> liftM Just parseExpression) <|> (return Nothing) - return (VarDecl pos id init) - -parseVarDeclStmt:: StatementParser st -parseVarDeclStmt = do - pos <- getPosition - reserved "var" - decls <- parseVarDecl `sepBy` comma - optional semi - return (VarDeclStmt pos decls) - -parseFunctionStmt:: StatementParser st -parseFunctionStmt = do - pos <- getPosition - name <- try (reserved "function" >> identifier) -- ambiguity with FuncExpr - args <- parens (identifier `sepBy` comma) - body <- parseBlockStmt <?> "function body in { ... }" - return (FunctionStmt pos name args body) - -parseStatement:: StatementParser st -parseStatement = parseIfStmt <|> parseSwitchStmt <|> parseWhileStmt - <|> parseDoWhileStmt <|> parseContinueStmt <|> parseBreakStmt - <|> parseBlockStmt <|> parseEmptyStmt <|> parseForInStmt <|> parseForStmt - <|> parseTryStmt <|> parseThrowStmt <|> parseReturnStmt <|> parseWithStmt - <|> parseVarDeclStmt <|> parseFunctionStmt - -- labelled, expression and the error message always go last, in this order - <|> parseLabelledStmt <|> parseExpressionStmt <?> "statement" - ---}}} - ---{{{ Expressions - --- References used to construct this stuff: --- + http://developer.mozilla.org/en/docs/ --- Core_JavaScript_1.5_Reference:Operators:Operator_Precedence --- + http://www.mozilla.org/js/language/grammar14.html --- --- Aren't expression tables nice? Well, we can't quite use them, because of --- JavaScript's ternary (?:) operator. We have to use two expression tables. --- We use one expression table for the assignment operators that bind looser --- than ?: (assignTable). The terms of assignTable are ternary expressions --- (parseTernaryExpr). parseTernaryExpr left-factors the left-recursive --- production for ?:, and is defined over the second expression table, --- exprTable, which consists of operators that bind tighter than ?:. The terms --- of exprTable are atomic expressions, parenthesized expressions, functions and --- array references. - ---{{{ Primary expressions - -parseThisRef:: ExpressionParser st -parseThisRef = do - pos <- getPosition - reserved "this" - return (ThisRef pos) - -parseNullLit:: ExpressionParser st -parseNullLit = do - pos <- getPosition - reserved "null" - return (NullLit pos) - - -parseBoolLit:: ExpressionParser st -parseBoolLit = do - pos <- getPosition - let parseTrueLit = reserved "true" >> return (BoolLit pos True) - parseFalseLit = reserved "false" >> return (BoolLit pos False) - parseTrueLit <|> parseFalseLit - -parseVarRef:: ExpressionParser st -parseVarRef = liftM2 VarRef getPosition identifier - -parseArrayLit:: ExpressionParser st -parseArrayLit = liftM2 ArrayLit getPosition (squares (parseExpression `sepBy` comma)) - -parseFuncExpr = do - pos <- getPosition - reserved "function" - args <- parens (identifier `sepBy` comma) - body <- parseBlockStmt - return $ FuncExpr pos args body - ---{{{ parsing strings - -escapeChars = - [('\'','\''),('\"','\"'),('\\','\\'),('b','\b'),('f','\f'),('n','\n'), - ('r','\r'),('t','\t'),('v','\v'),('/','/')] - -allEscapes:: String -allEscapes = map fst escapeChars - -parseEscapeChar = do - c <- oneOf allEscapes - let (Just c') = lookup c escapeChars -- will succeed due to line above - return c' - -parseAsciiHexChar = do - char 'x' - d1 <- hexDigit - d2 <- hexDigit - return ((chr.fst.head.readHex) (d1:d2:"")) - -parseUnicodeHexChar = do - char 'u' - liftM (chr.fst.head.readHex) - (sequence [hexDigit,hexDigit,hexDigit,hexDigit]) - -isWhitespace ch = ch `elem` " \t" - - --- The endWith argument is either single-quote or double-quote, depending on how --- we opened the string. -parseStringLit' endWith = - (char endWith >> return "") <|> - (do try (string "\\'") - cs <- parseStringLit' endWith - return $ "'" ++ cs) <|> - (do char '\\' - c <- parseEscapeChar <|> parseAsciiHexChar <|> parseUnicodeHexChar <|> - char '\r' <|> char '\n' - cs <- parseStringLit' endWith - if c == '\r' || c == '\n' - then return (c:(dropWhile isWhitespace cs)) - else return (c:cs)) <|> - (liftM2 (:) anyChar (parseStringLit' endWith)) - -parseStringLit:: ExpressionParser st -parseStringLit = do - pos <- getPosition - -- parseStringLit' takes as an argument the quote-character that opened the - -- string. - str <- lexeme $ (char '\'' >>= parseStringLit') <|> (char '\"' >>= parseStringLit') - -- CRUCIAL: Parsec.Token parsers expect to find their token on the first - -- character, and read whitespaces beyond their tokens. Without 'lexeme' - -- above, expressions like: - -- var s = "string" ; - -- do not parse. - return $ StringLit pos str - ---}}} - -parseRegexpLit:: ExpressionParser st -parseRegexpLit = do - let parseFlags = do - flags <- many (oneOf "mgi") - return $ \f -> f ('g' `elem` flags) ('i' `elem` flags) - let parseEscape = char '\\' >> anyChar - let parseChar = noneOf "/" - let parseRe = (char '/' >> return "") <|> - (do char '\\' - ch <- anyChar -- TOOD: too lenient - rest <- parseRe - return ('\\':ch:rest)) <|> - (liftM2 (:) anyChar parseRe) - pos <- getPosition - char '/' - pat <- parseRe --many1 parseChar - flags <- parseFlags - spaces -- crucial for Parsec.Token parsers - return $ flags (RegexpLit pos pat) - -parseObjectLit:: ExpressionParser st -parseObjectLit = - let parseProp = do - -- Parses a string, identifier or integer as the property name. I - -- apologize for the abstruse style, but it really does make the code - -- much shorter. - name <- (liftM (uncurry PropString) - (liftM (\(StringLit p s) -> (p,s)) parseStringLit)) - <|> (liftM2 PropId getPosition identifier) - <|> (liftM2 PropNum getPosition decimal) - colon - val <- parseAssignExpr - return (name,val) - in do pos <- getPosition - props <- braces (parseProp `sepEndBy` comma) <?> "object literal" - return $ ObjectLit pos props - ---{{{ Parsing numbers. From pg. 17-18 of ECMA-262. - -hexLit = do - try (string "0x") - digits <- many1 (oneOf "0123456789abcdefABCDEF") - [(hex,"")] <- return $ Numeric.readHex digits - return hex - --- Creates a decimal value from a whole, fractional and exponent part. -mkDecimal:: Double -> Double -> Int -> Double -mkDecimal w f e = - if (f >= 1.0) - then mkDecimal w (f / 10.0) e - else (w + f) * (10.0 ^^ e) - -exponentPart = do - oneOf "eE" - (char '+' >> decimal) <|> (char '-' >> negate `fmap` decimal) <|> decimal - -decLit = - (do whole <- decimal - frac <- option 0 (char '.' >> decimal) - exp <- option 0 exponentPart - return $ mkDecimal (fromIntegral whole) (fromIntegral frac) (fromIntegral exp)) <|> - (do frac <- char '.' >> decimal - exp <- option 0 exponentPart - return $ mkDecimal 0.0 (fromIntegral frac) (fromIntegral exp)) - -parseNumLit:: ExpressionParser st -parseNumLit = do - pos <- getPosition - num <- lexeme $ hexLit <|> decLit - notFollowedBy identifierStart <?> "whitespace" - return $ NumLit pos num - ---}}} - ------------------------------------------------------------------------------- --- Position Helper ------------------------------------------------------------------------------- - -withPos cstr p = do { pos <- getPosition; e <- p; return $ cstr pos e } - -------------------------------------------------------------------------------- --- Compound Expression Parsers -------------------------------------------------------------------------------- - -dotRef e = (reservedOp "." >> withPos cstr identifier) <?> "property.ref" - where cstr pos key = DotRef pos e key - -funcApp e = (parens $ withPos cstr (parseExpression `sepBy` comma)) <?> "(function application)" - where cstr pos args = CallExpr pos e args - -bracketRef e = (brackets $ withPos cstr parseExpression) <?> "[property-ref]" - where cstr pos key = BracketRef pos e key - -------------------------------------------------------------------------------- --- Expression Parsers -------------------------------------------------------------------------------- - -parseParenExpr:: ExpressionParser st -parseParenExpr = withPos ParenExpr (parens parseListExpr) - --- everything above expect functions -parseExprForNew = parseThisRef <|> parseNullLit <|> parseBoolLit <|> parseStringLit - <|> parseArrayLit <|> parseParenExpr <|> parseNewExpr <|> parseNumLit - <|> parseRegexpLit <|> parseObjectLit <|> parseVarRef - --- all the expression parsers defined above -parseSimpleExpr' = parseThisRef <|> parseNullLit <|> parseBoolLit - <|> parseStringLit <|> parseArrayLit <|> parseParenExpr - <|> parseFuncExpr <|> parseNumLit <|> parseRegexpLit <|> parseObjectLit - <|> parseVarRef - -parseNewExpr = - (do pos <- getPosition - reserved "new" - constructor <- parseSimpleExprForNew Nothing -- right-associativity - arguments <- (try (parens (parseExpression `sepBy` comma))) <|> (return []) - return (NewExpr pos constructor arguments)) <|> - parseSimpleExpr' - -parseSimpleExpr (Just e) = (do - e' <- dotRef e <|> funcApp e <|> bracketRef e - parseSimpleExpr $ Just e') <|> (return e) -parseSimpleExpr Nothing = do - e <- parseNewExpr <?> "expression (3)" - parseSimpleExpr (Just e) - -parseSimpleExprForNew (Just e) = (do - e' <- dotRef e <|> bracketRef e - parseSimpleExprForNew $ Just e') <|> (return e) -parseSimpleExprForNew Nothing = do - e <- parseNewExpr <?> "expression (3)" - parseSimpleExprForNew (Just e) - ---}}} - -makeInfixExpr str constr = Infix parser AssocLeft where - parser:: CharParser st (Expression SourcePos -> Expression SourcePos -> Expression SourcePos) - parser = do - pos <- getPosition - reservedOp str - return (InfixExpr pos constr) -- points-free, returns a function - -makePrefixExpr str constr = Prefix parser where - parser = do - pos <- getPosition - (reservedOp str <|> reserved str) - return (PrefixExpr pos constr) -- points-free, returns a function - -mkPrefix operator constr = Prefix $ do - pos <- getPosition - operator - return (\operand -> PrefixExpr pos constr operand) - -makePostfixExpr str constr = Postfix parser where - parser = do - pos <- getPosition - (reservedOp str <|> reserved str) - return (PostfixExpr pos constr) -- points-free, returns a function - -prefixIncDecExpr = do - pos <- getPosition - op <- optionMaybe $ (reservedOp "++" >> return PrefixInc) <|> - (reservedOp "--" >> return PrefixDec) - case op of - Nothing -> parseSimpleExpr Nothing - Just op -> do - innerExpr <- parseSimpleExpr Nothing -- TODO: must be an l-val, I think - return (PrefixExpr pos op innerExpr) - --- apparently, expression tables can't handle immediately-nested prefixes - -parsePrefixedExpr = do - pos <- getPosition - op <- optionMaybe $ (reservedOp "!" >> return PrefixLNot) <|> - (reservedOp "~" >> return PrefixBNot) <|> - (try (lexeme $ char '-' >> notFollowedBy (char '-')) >> - return PrefixMinus) <|> - (try (lexeme $ char '+' >> notFollowedBy (char '+')) >> - return PrefixPlus) <|> - (reserved "typeof" >> return PrefixTypeof) <|> - (reserved "void" >> return PrefixVoid) <|> - (reserved "delete" >> return PrefixDelete) - case op of - Nothing -> prefixIncDecExpr -- new is treated as a simple expr - Just op -> do - innerExpr <- parsePrefixedExpr - return (PrefixExpr pos op innerExpr) - -exprTable:: [[Operator Char st ParsedExpression]] -exprTable = - [ - [makePrefixExpr "++" PrefixInc, - makePostfixExpr "++" PostfixInc], - [makePrefixExpr "--" PrefixDec, - makePostfixExpr "--" PostfixDec], - [makeInfixExpr "*" OpMul, makeInfixExpr "/" OpDiv, makeInfixExpr "%" OpMod], - [makeInfixExpr "+" OpAdd, makeInfixExpr "-" OpSub], - [makeInfixExpr "<<" OpLShift, makeInfixExpr ">>" OpSpRShift, - makeInfixExpr ">>>" OpZfRShift], - [makeInfixExpr "<" OpLT, makeInfixExpr "<=" OpLEq, makeInfixExpr ">" OpGT, - makeInfixExpr ">=" OpGEq, - makeInfixExpr "instanceof" OpInstanceof, makeInfixExpr "in" OpIn], - [makeInfixExpr "&" OpBAnd], - [makeInfixExpr "^" OpBXor], - [makeInfixExpr "|" OpBOr], - [makeInfixExpr "&&" OpLAnd], - [makeInfixExpr "||" OpLOr], - [makeInfixExpr "==" OpEq, makeInfixExpr "!=" OpNEq, - makeInfixExpr "===" OpStrictEq, makeInfixExpr "!==" OpStrictNEq] - ] - -parseExpression' = - buildExpressionParser exprTable parsePrefixedExpr <?> "simple expression" - ---{{{ Parsing ternary operators: left factored - -parseTernaryExpr':: CharParser st (ParsedExpression,ParsedExpression) -parseTernaryExpr' = do - reservedOp "?" - l <- parseAssignExpr - colon - r <- parseAssignExpr - return $(l,r) - -parseTernaryExpr:: ExpressionParser st -parseTernaryExpr = do - e <- parseExpression' - e' <- optionMaybe parseTernaryExpr' - case e' of - Nothing -> return e - Just (l,r) -> do p <- getPosition - return $ CondExpr p e l r ---}}} - --- Parsing assignment operations. -makeAssignExpr str constr = Infix parser AssocRight where - parser:: CharParser st (ParsedExpression -> ParsedExpression -> ParsedExpression) - parser = do - pos <- getPosition - reservedOp str - return (AssignExpr pos constr) - -assignTable:: [[Operator Char st ParsedExpression]] -assignTable = [ - [makeAssignExpr "=" OpAssign, makeAssignExpr "+=" OpAssignAdd, - makeAssignExpr "-=" OpAssignSub, makeAssignExpr "*=" OpAssignMul, - makeAssignExpr "/=" OpAssignDiv, makeAssignExpr "%=" OpAssignMod, - makeAssignExpr "<<=" OpAssignLShift, makeAssignExpr ">>=" OpAssignSpRShift, - makeAssignExpr ">>>=" OpAssignZfRShift, makeAssignExpr "&=" OpAssignBAnd, - makeAssignExpr "^=" OpAssignBXor, makeAssignExpr "|=" OpAssignBOr - ]] - - -parseAssignExpr:: ExpressionParser st -parseAssignExpr = buildExpressionParser assignTable parseTernaryExpr - -parseExpression:: ExpressionParser st -parseExpression = parseAssignExpr - -parseListExpr = - liftM2 ListExpr getPosition (parseAssignExpr `sepBy1` comma) - ---}}} - -parseScript:: CharParser state (JavaScript SourcePos) -parseScript = do - whiteSpace - liftM2 Script getPosition (parseStatement `sepBy` whiteSpace) - -parseJavaScriptFromFile :: MonadIO m => String -> m [Statement SourcePos] -parseJavaScriptFromFile filename = do - chars <- liftIO $ readFile filename - case parse parseScript filename chars of - Left err -> fail (show err) - Right (Script _ stmts) -> return stmts - - -parseScriptFromString:: String -> String -> Either ParseError (JavaScript SourcePos) -parseScriptFromString src script = parse parseScript src script - -emptyParsedJavaScript = - Script (error "Parser.emptyParsedJavaScript--no annotation") [] - -parseString :: String -> [Statement SourcePos] -parseString str = case parse parseScript "" str of - Left err -> error (show err) - Right (Script _ stmts) -> stmts
− src/WebBits/JavaScript/PrettyPrint.hs
@@ -1,261 +0,0 @@--- |Pretty-printing JavaScript. This module doesn't export any names, but--- importing it declares PrettyPrintable instances for JavaScript.Syntax.-module WebBits.JavaScript.PrettyPrint() where--import Text.PrettyPrint.HughesPJ-import WebBits.JavaScript.Syntax-import WebBits.JavaScript.Combinators-import WebBits.Common----{{{ Helper functions for common printing patterns---- Displays the statement in { ... }, unless it already is in a block.-inBlock:: (Statement a) -> Doc-inBlock stmt@(BlockStmt _ _) = pp stmt-inBlock stmt = text "{" $+$ pp stmt $+$ text "}"---- Displays the expression in ( ... ), unless it already is in parens.-inParens:: (Expression a) -> Doc-inParens expr@(ParenExpr _ _) = pp expr-inParens expr = parens (pp expr)--commaSep:: (PrettyPrintable a) => [a] -> Doc-commaSep = hsep.(punctuate comma).(map pp)----}}}--instance PrettyPrintable (Id a) where- pp (Id _ str) = text str--instance PrettyPrintable (ForInit a) where- pp NoInit = empty- pp (VarInit vs) = text "var" <+> commaSep vs - pp (ExprInit e) = pp e- -instance PrettyPrintable (ForInInit a) where- pp (ForInVar id) = text "var" <+> pp id- pp (ForInNoVar id) = pp id----{{{ Pretty-printing statements--instance PrettyPrintable (CaseClause a) where- pp (CaseClause _ expr stmts) =- text "case" $+$ pp expr <+> colon $$ (nest 2 (vcat (map pp stmts)))- pp (CaseDefault _ stmts) =- text "default:" $$ (nest 2 (vcat (map pp stmts)))--instance PrettyPrintable (CatchClause a) where- pp (CatchClause _ id stmt) =- text "catch" <+> (parens.pp) id <+> inBlock stmt---instance PrettyPrintable (VarDecl a) where- pp (VarDecl _ id Nothing) =- pp id- pp (VarDecl _ id (Just expr)) =- pp id <+> equals <+> pp expr--instance PrettyPrintable (Statement a) where- pp (BlockStmt _ stmts) =- text "{" $+$ nest 2 (vcat (map pp stmts)) $+$ text "}"- pp (EmptyStmt _) =- semi- pp (ExprStmt _ expr) =- pp expr <> semi- pp (IfSingleStmt _ test cons) =- text "if" <+> inParens test $$ (nest 2 (pp cons))- pp (IfStmt _ test cons alt) =- text "if" <+> inParens test $$ (nest 2 $ pp cons) $$ text "else"- $$ (nest 2 $ pp alt)- pp (SwitchStmt _ expr cases) =- text "switch" <+> inParens expr $$ braces (nest 2 (vcat (map pp cases)))- pp (WhileStmt _ test body) =- text "while" <+> inParens test $$ (nest 2 (pp body))- pp (ReturnStmt _ expr) =- text "return" <+> pp expr <> semi- pp (DoWhileStmt _ stmt expr) =- text "do" $$ (nest 2 (pp stmt <+> text "while" <+> inParens expr))- pp (BreakStmt _ Nothing) =- text "break;"- pp (BreakStmt _ (Just label)) =- text "break" <+> pp label <> semi- pp (ContinueStmt _ Nothing) =- text "continue;"- pp (ContinueStmt _ (Just label)) =- text"continue" <+> pp label <> semi- pp (LabelledStmt _ label stmt) =- pp label <> colon $$ pp stmt- pp (ForInStmt p init expr body) =- text "for" <+> parens (pp init <+> text "in" <+> pp expr)- $$ (nest 2 (pp body))- pp (ForStmt _ init incr test body) =- text "for" <+> parens (pp init <> semi <+> pp incr <> semi <+> pp test)- $$ (nest 2 (pp body))- pp (TryStmt _ stmt catches finally) =- text "try" $$ inBlock stmt $$ (vcat (map pp catches)) $$ ppFinally where - ppFinally = case finally of- Nothing -> empty- Just stmt -> text "finally" <> inBlock stmt- pp (ThrowStmt _ expr) =- text "throw" <+> pp expr <> semi- pp (WithStmt _ expr stmt) | isParenExpr expr =- (text "with" <+> inParens expr $$ pp stmt)- pp (WithStmt _ expr stmt) | otherwise =- (text "with" <+> inParens expr $$ pp stmt)- pp (VarDeclStmt _ decls) =- text "var" <+> commaSep decls <> semi- pp (FunctionStmt _ name args stmt) =- text "function" <+> pp name <> (parens.commaSep) args $$ inBlock stmt----}}}--instance PrettyPrintable (Prop a) where- pp (PropId _ id) = pp id- pp (PropString _ str) = doubleQuotes (text (jsEscape str))- pp (PropNum _ n) = text (show n)-----{{{ infix-operators--showInfix op =- case op of- OpMul -> "*"- OpDiv -> "/"- OpMod -> "%" - OpAdd -> "+" - OpSub -> "-"- OpLShift -> "<<"- OpSpRShift -> ">>"- OpZfRShift -> ">>>"- OpLT -> "<"- OpLEq -> "<="- OpGT -> ">"- OpGEq -> ">="- OpIn -> "in"- OpInstanceof -> "instanceof"- OpEq -> "=="- OpNEq -> "!="- OpStrictEq -> "==="- OpStrictNEq -> "!=="- OpBAnd -> "&"- OpBXor -> "^"- OpBOr -> "|"- OpLAnd -> "&&"- OpLOr -> "||"--instance PrettyPrintable InfixOp where- pp op = text (showInfix op)---}}}----{{{ prefix operators--showPrefix PrefixInc = "++"-showPrefix PrefixDec = "--"-showPrefix PrefixLNot = "!"-showPrefix PrefixBNot = "~"-showPrefix PrefixPlus = "+"-showPrefix PrefixMinus = "-"-showPrefix PrefixTypeof = "typeof"-showPrefix PrefixVoid = "void"-showPrefix PrefixDelete = "delete"--instance PrettyPrintable PrefixOp where- pp op = text (showPrefix op)----}}}----{{{ postfix operators--instance PrettyPrintable PostfixOp where- pp PostfixInc = text "++"- pp PostfixDec = text "--"----}}}----{{{ assignment operators--showAssignOp OpAssign = "="-showAssignOp OpAssignAdd = "+="-showAssignOp OpAssignSub = "-="-showAssignOp OpAssignMul = "*="-showAssignOp OpAssignDiv = "/="-showAssignOp OpAssignMod = "%="-showAssignOp OpAssignLShift = "<<="-showAssignOp OpAssignSpRShift = ">>="-showAssignOp OpAssignZfRShift = ">>>="-showAssignOp OpAssignBAnd = "&="-showAssignOp OpAssignBXor = "^="-showAssignOp OpAssignBOr = "|="--instance PrettyPrintable AssignOp where- pp = text.showAssignOp----}}}----{{{ expressions---- Based on:--- http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals-jsEscape:: String -> String-jsEscape "" = ""-jsEscape (ch:chs) = (sel ch) ++ jsEscape chs where- sel '\b' = "\\b"- sel '\f' = "\\f"- sel '\n' = "\\n"- sel '\r' = "\\r"- sel '\t' = "\\t"- sel '\v' = "\\v"- sel '\'' = "\\'"- sel '\"' = "\\\""- sel '\\' = "\\\\"- sel x = [x]- -- We don't have to do anything about \X, \x and \u escape sequences.-- -instance PrettyPrintable (Expression a) where- pp (StringLit _ str) = doubleQuotes (text (jsEscape str))- pp (RegexpLit _ re global ci) =- text "/" <> text re <> text "/" <> g <> i where- g = if global then text "g" else empty- i = if ci then text "i" else empty- pp (NumLit _ n) = text (show n)- pp (BoolLit _ True) = text "true"- pp (BoolLit _ False) = text "false"- pp (NullLit _) = text "null"- pp (ArrayLit _ xs) = - (brackets.commaSep) xs- pp (ObjectLit _ xs) = - braces (hsep (punctuate comma (map pp' xs))) where- pp' (n,v) = pp n <> colon <+> pp v- pp (ThisRef _) = text "this"- pp (VarRef _ id) = pp id- pp (DotRef _ expr id) =- pp expr <> text "." <> pp id- pp (BracketRef _ container key) =- pp container <> brackets (pp key)- pp (NewExpr _ constr args) =- text "new" <+> pp constr <> (parens.commaSep) args- pp (PrefixExpr _ op expr) =- pp op <+> pp expr- pp (PostfixExpr _ op expr) =- pp expr <+> pp op- pp (InfixExpr _ op left right) = - pp left <+> pp op <+> pp right- pp (CondExpr _ test cons alt) =- pp test <+> text "?" <+> pp cons <+> colon <+> pp alt- pp (AssignExpr _ op l r) =- pp l <+> pp op <+> pp r- pp (ParenExpr _ expr) =- parens (pp expr)- pp (ListExpr _ exprs) = commaSep exprs- pp (CallExpr _ f args) =- pp f <> (parens.commaSep) args- pp (FuncExpr _ args body) =- text "function" <+> (parens.commaSep) args $$ inBlock body--instance PrettyPrintable (JavaScript a) where- pp (Script _ stmts) =- vcat (map pp stmts)----}}}-
− src/WebBits/JavaScript/Syntax.hs
@@ -1,117 +0,0 @@--- |JavaScript's syntax. -module WebBits.JavaScript.Syntax(Expression(..),CaseClause(..),Statement(..), - InfixOp(..),CatchClause(..),VarDecl(..),JavaScript(..), - AssignOp(..),Id(..),PrefixOp(..),PostfixOp(..),Prop(..), - ForInit(..),ForInInit(..)) where - -import Text.ParserCombinators.Parsec(SourcePos) -- used by data JavaScript -import Data.Generics(Data,Typeable) - -data JavaScript a - -- |A script in <script> ... </script> tags. This may seem a little silly, - -- but the Flapjax analogue has an inline variant and attribute-inline - -- variant. - = Script a [Statement a] - deriving (Show,Data,Typeable,Eq,Ord) - -data Id a = Id a String deriving (Show,Eq,Ord,Data,Typeable) - --- http://developer.mozilla.org/en/docs/ --- Core_JavaScript_1.5_Reference:Operators:Operator_Precedence -data InfixOp = OpLT | OpLEq | OpGT | OpGEq | OpIn | OpInstanceof | OpEq | OpNEq - | OpStrictEq | OpStrictNEq | OpLAnd | OpLOr - | OpMul | OpDiv | OpMod | OpSub | OpLShift | OpSpRShift - | OpZfRShift | OpBAnd | OpBXor | OpBOr | OpAdd - deriving (Show,Data,Typeable,Eq,Ord,Enum) - -data AssignOp = OpAssign | OpAssignAdd | OpAssignSub | OpAssignMul | OpAssignDiv - | OpAssignMod | OpAssignLShift | OpAssignSpRShift | OpAssignZfRShift - | OpAssignBAnd | OpAssignBXor | OpAssignBOr - deriving (Show,Data,Typeable,Eq,Ord) - -data PrefixOp = PrefixInc | PrefixDec | PrefixLNot | PrefixBNot | PrefixPlus - | PrefixMinus | PrefixTypeof | PrefixVoid | PrefixDelete - deriving (Show,Data,Typeable,Eq,Ord) - -data PostfixOp - = PostfixInc | PostfixDec - deriving (Show,Data,Typeable,Eq,Ord) - -data Prop a - = PropId a (Id a) | PropString a String | PropNum a Integer - deriving (Show,Data,Typeable,Eq,Ord) - -data Expression a - = StringLit a String - | RegexpLit a String Bool {- global? -} Bool {- case-insensitive? -} - | NumLit a Double -- pg. 5 of ECMA-262 - | BoolLit a Bool - | NullLit a - | ArrayLit a [Expression a] - | ObjectLit a [(Prop a, Expression a)] - | ThisRef a - | VarRef a (Id a) - | DotRef a (Expression a) (Id a) - | BracketRef a (Expression a) {- container -} (Expression a) {- key -} - | NewExpr a (Expression a) {- constructor -} [Expression a] - | PostfixExpr a PostfixOp (Expression a) - | PrefixExpr a PrefixOp (Expression a) - | InfixExpr a InfixOp (Expression a) (Expression a) - | CondExpr a (Expression a) (Expression a) (Expression a) - | AssignExpr a AssignOp (Expression a) (Expression a) - | ParenExpr a (Expression a) - | ListExpr a [Expression a] - | CallExpr a (Expression a) [Expression a] - | FuncExpr a [(Id a)] (Statement a) - deriving (Show,Data,Typeable,Eq,Ord) - -data CaseClause a - = CaseClause a (Expression a) [Statement a] - | CaseDefault a [Statement a] - deriving (Show,Data,Typeable,Eq,Ord) - -data CatchClause a - = CatchClause a (Id a) (Statement a) - deriving (Show,Data,Typeable,Eq,Ord) - -data VarDecl a - = VarDecl a (Id a) (Maybe (Expression a)) - deriving (Show,Data,Typeable,Eq,Ord) - -data ForInit a - = NoInit - | VarInit [VarDecl a] - | ExprInit (Expression a) - deriving (Show,Data,Typeable,Eq,Ord) - -data ForInInit a - = ForInVar (Id a) - | ForInNoVar (Id a) - deriving (Show,Data,Typeable,Eq,Ord) - - -data Statement a - = BlockStmt a [Statement a] - | EmptyStmt a - | ExprStmt a (Expression a) - | IfStmt a (Expression a) (Statement a) (Statement a) - | IfSingleStmt a (Expression a) (Statement a) - | SwitchStmt a (Expression a) [CaseClause a] - | WhileStmt a (Expression a) (Statement a) - | DoWhileStmt a (Statement a) (Expression a) - | BreakStmt a (Maybe (Id a)) - | ContinueStmt a (Maybe (Id a)) - | LabelledStmt a (Id a) (Statement a) - | ForInStmt a (ForInInit a) (Expression a) (Statement a) - | ForStmt a (ForInit a) - (Maybe (Expression a)) -- increment - (Maybe (Expression a)) -- test - (Statement a) -- body - | TryStmt a (Statement a) {-body-} [CatchClause a] {-catches-} - (Maybe (Statement a)) {-finally-} - | ThrowStmt a (Expression a) - | ReturnStmt a (Maybe (Expression a)) - | WithStmt a (Expression a) (Statement a) - | VarDeclStmt a [VarDecl a] - | FunctionStmt a (Id a) {-name-} [(Id a)] {-args-} (Statement a) {-body-} - deriving (Show,Data,Typeable,Eq,Ord)