packages feed

yi-0.6.0: Yi/Lexer/JavaScript.x

-- -*- haskell -*-
--
-- Simple lexer for JavaScript 1.7
-- (C) Copyright 2009 Deniz Dogan
--
-- Note that this mode is for JavaScript 1.7, i.e. Mozilla, not ECMAScript, nor
-- JScript, but it does take much of its information from the ECMAScript
-- specification.
--
-- Things about JavaScript deserve to be mentioned:
-- * JavaScript explicitly forbids nested comments, so we don't have to care
--   about the "level" of nesting in multiline comments
--
-- Sources for reserved words:
-- https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Reserved_Words
-- https://developer.mozilla.org/en/New_in_JavaScript_1.6
-- https://developer.mozilla.org/en/New_in_JavaScript_1.7
--
-- Sources for the general syntax:
-- http://en.wikipedia.org/wiki/JavaScript_syntax
-- http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

{

{-# OPTIONS -w  #-}

module Yi.Lexer.JavaScript ( initState,
                             alexScanToken,
                             tokenToStyle,
                             isSpecial,
                             TT,
                             Token(..),
                             Reserved(..),
                             Operator(..) ) where

import Yi.Lexer.Alex
import Yi.Style

}

$whitechar  = [\ \t\n\r\f\v]

@builtin    = true | false | null | undefined
@reservedid = break | case | catch | continue | default | delete | do | else
            | finally | for | function | if | in | instanceof | new | return
            | switch | this | throw | try | typeof | var | void | while | with
            | @builtin

@ops = "+"   | "-"   | "*"   | "/"   | "%"   | "++"  | "--"  | "="   | "+="
     | "-="  | "*="  | "/="  | "%="  | "=="  | "!="  | ">"   | ">="  | "<"
     | "<="  | "===" | "!==" | "&&"  |"||"   | "!"   | "&"   | "|"   | "^"
     | "<<"  | ">>"  | ">>>" | "~"

$large     = [A-Z \xc0-\xd6 \xd8-\xde]
$small     = [a-z \xdf-\xf6 \xf8-\xff]
$special   = [\(\)\,\;\[\]\`\{\}\.\:]

$ascdigit  = 0-9
$unidigit  = [] -- TODO
$digit     = [$ascdigit $unidigit]

$ascsymbol = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\_]
$unisymbol = [] -- TODO
$symbol    = [$ascsymbol $unisymbol] # [$special \:\"\']
$graphic   = [$small $large $symbol $digit $special \:\"\']
$cntrl     = [$large \@\[\\\]\^\_]
$name      = [a-zA-Z0-9\_\$] -- Valid characters for a "name"

@number  = $digit+ -- TODO: Hexadecimal/octals/exponent notation
@ascii   = \^ $cntrl | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS  | HT
         | LF  | VT  | FF  | CR  | SO  | SI  | DLE | DC1 | DC2 | DC3 | DC4 | NAK
         | SYN | ETB | CAN | EM  | SUB | ESC | FS  | GS  | RS  | US  | SP  | DEL
$charesc = [abfnrtv\\\"\'\&]
@escape  = \\ ($charesc | @ascii | @number)
@gap     = \\ $whitechar+ \\
@string  = $graphic # [\"\\] | " " | @escape | @gap

-- @varid represents valid names for variables and functions.
@varid   = [$name # [0-9A-Z]] $name*
@const   = [$name # [0-9a-z]] $name* -- Constants and constructors

haskell :-

<0> {

$whitechar+            ;
$special               { cs $ (Special . head) } -- All of the special symbols are characters

@number                { cs $ Number }
@ops                   { cs $ (Op . opToOp) }
@reservedid            { cs $ (Res . resToRes) }
@varid                 { cs $ ValidName }
@const                 { cs $ Const }

\" @string* \"         { cs $ Str }
\' @string* \'         { cs $ Str }
"//".*                 { c  $ Comment Line }
"/*"                   { m (subtract 1) $ Comment Start }

.                      { cs $ Unknown }

}

<multicomm> { -- I refrain from calling this "nestcomm" since nested comments
              -- aren't allowed in JavaScript.

"*/"    { m (+1) $ Comment End }
.       { c $ Comment Text }
$whitechar+ ;

}


{

type TT = Tok Token

-- | The @Line@ constructor represents a single-line comment.  @Start@ and @End@
--   represent the start and end of a multi-line comment, respectively.  @Text@
--   represents the text in a multi-line comment.
data CommentType = Line | Start | End | Text
                 deriving (Show, Eq)

-- | The constructors for @Reserved@ have an apostrophe as a suffix because
--   @Default@ is already used.  Also note that @Undefined'@ is not intended as
--   some sort of "backup" reserved word for things we don't care about -- it
--   really means the "undefined" built-in in JavaScript.
data Reserved = Break' | Case' | Catch' | Continue' | Default' | Delete' | Do'
              | Else' | Finally' | For' | Function' | If' | In' | InstanceOf'
              | New' | Return' | Switch' | This' | Throw' | Try' | TypeOf'
              | Var' | Void' | While' | With' | True' | False' | Null'
              | Undefined'
                deriving (Show, Eq)

-- | The constructors for @Operator@ have an apostrophe as a suffix because
--   e.g. @LT@ is already used by @Prelude@.
data Operator = Add' | Subtract' | Multiply' | Divide' | Modulo' | Increment'
              | Decrement' | Assign' | AddAssign' | SubtractAssign'
              | MultiplyAssign' | DivideAssign' | ModuloAssign' | Equals'
              | NotEquals' | GT' | GTE' | LT' | LTE' | EqualsType'
              | NotEqualsType' | And' | Or' | Not' | BitAnd' | BitOr' | BitXor'
              | LeftShift' | RightShift' | RightShiftZ' | BitNot'
                deriving (Show, Eq)

-- | @HlState@ is 0 when outside of a multi-line comment and -1 when inside one.
type HlState = Int

-- | The different tokens.
data Token = Unknown !String
           | Res !Reserved
           | Str !String
           | Op !Operator
           | Special !Char
           | Number !String
           | ValidName !String
           | Comment !CommentType
           | Const !String
             deriving (Show, Eq)

stateToInit x | x < 0     = multicomm
              | otherwise = 0

initState :: HlState
initState = 0

isSpecial :: Token -> Bool
isSpecial (Special _) = True
isSpecial _           = False

-- | Takes a 'Token' and returns a style to be used for that type of token.
tokenToStyle (Comment Line) = commentStyle
tokenToStyle (Comment _)    = blockCommentStyle
tokenToStyle (Const _)      = typeStyle
tokenToStyle (Number _)     = numberStyle
tokenToStyle (Op _)         = defaultStyle
tokenToStyle (Res _)        = keywordStyle
tokenToStyle (Special _)    = defaultStyle
tokenToStyle (Str _)        = stringStyle
tokenToStyle (Unknown _)    = errorStyle
tokenToStyle (ValidName _)   = defaultStyle

-- | Given a @String@ representing an operator, returns an 'Operator' with the
--   appropriate constructor.
opToOp :: String -> Operator
opToOp "+"   = Add'
opToOp "-"   = Subtract'
opToOp "*"   = Multiply'
opToOp "/"   = Divide'
opToOp "%"   = Modulo'
opToOp "++"  = Increment'
opToOp "--"  = Decrement'
opToOp "="   = Assign'
opToOp "+="  = AddAssign'
opToOp "-="  = SubtractAssign'
opToOp "*="  = MultiplyAssign'
opToOp "/="  = DivideAssign'
opToOp "%="  = ModuloAssign'
opToOp "=="  = Equals'
opToOp "!="  = NotEquals'
opToOp ">"   = GT'
opToOp ">="  = GTE'
opToOp "<"   = LT'
opToOp "<="  = LTE'
opToOp "===" = EqualsType'
opToOp "!==" = NotEqualsType'
opToOp "&&"  = And'
opToOp "||"  = Or'
opToOp "!"   = Not'
opToOp "&"   = BitAnd'
opToOp "|"   = BitOr'
opToOp "^"   = BitXor'
opToOp "<<"  = LeftShift'
opToOp ">>"  = RightShift'
opToOp ">>>" = RightShiftZ'
opToOp "~"   = BitNot'

-- | Given a @String@ representing a reserved word, returns a 'Reserved' with
--   the appropriate constructor.
resToRes :: String -> Reserved
resToRes "break"      = Break'
resToRes "case"       = Case'
resToRes "catch"      = Catch'
resToRes "continue"   = Continue'
resToRes "default"    = Default'
resToRes "delete"     = Delete'
resToRes "do"         = Do'
resToRes "else"       = Else'
resToRes "finally"    = Finally'
resToRes "for"        = For'
resToRes "function"   = Function'
resToRes "if"         = If'
resToRes "in"         = In'
resToRes "instanceof" = InstanceOf'
resToRes "new"        = New'
resToRes "return"     = Return'
resToRes "switch"     = Switch'
resToRes "this"       = This'
resToRes "throw"      = Throw'
resToRes "try"        = Try'
resToRes "typeof"     = TypeOf'
resToRes "var"        = Var'
resToRes "void"       = Void'
resToRes "while"      = While'
resToRes "with"       = With'
resToRes "true"       = True'
resToRes "false"      = False'
resToRes "null"       = Null'
resToRes "undefined"  = Undefined'

#include "alex.hsinc"
}