public
Description: Haskell implemented JavaScript interpreter
Homepage:
Clone URL: git://github.com/motemen/jusk.git
jusk / JSType.hs
100644 213 lines (157 sloc) 5.583 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
{-
JSType.hs
型変換
-}
 
module JSType where
import Prelude hiding (toInteger)
 
import DataTypes
import Parser (numericLiteral)
import ParserUtil (runLex)
import Internal
import Eval
 
toPrimitive :: Value -> String -> Evaluate Value
toPrimitive Undefined _ =
    return Undefined
 
toPrimitive Null _ =
    return Null
 
toPrimitive bool@(Boolean _) _ =
    return bool
 
toPrimitive num@(Number _) _ =
    return num
 
toPrimitive string@(String _) _ =
    return string
 
toPrimitive ref@(Reference { }) preferredType =
    flip toPrimitive preferredType =<< getValue ref
 
toPrimitive ref@(Ref _) preferredType =
    flip toPrimitive preferredType =<< readRef ref
 
toPrimitive object preferredType =
    defaultValue object preferredType
 
toBoolean :: Value -> Evaluate Bool
toBoolean Undefined = return False
toBoolean Null = return False
 
toBoolean (Boolean bool) = return bool
 
toBoolean (Number NaN) = return False
toBoolean (Number (Double n)) = return $ n /= 0
toBoolean (Number (Integer n)) = return $ n /= 0
 
toBoolean (String string) = return $ not $ null string
 
toBoolean Object { } = return True
 
toBoolean o = getValue o >>= readRef >>= toBoolean
 
toNumber :: Value -> Evaluate Number
toNumber Undefined =
    return NaN
 
toNumber Null =
    return $ Integer 0
 
toNumber (Boolean bool) =
    return $ if bool then Integer 1
                     else Double 0.0
 
toNumber (Number num) =
    return num
 
toNumber (String string) =
    case runLex numericLiteral string of
         Left _ -> return NaN
         Right (Literal (Number n)) -> return n
 
toNumber object@Object { } =
    toPrimitive object "Number" >>= toNumber
 
toNumber ref@Ref { } =
    readRef ref >>= toNumber
 
toNumber ref@Reference { } =
    getValue ref >>= toNumber
 
toNumber o =
    (throw "NotImplemented" $ "toNumber: " ++ show o) >> return NaN
 
toInteger :: Value -> Evaluate Integer
toInteger (Number NaN) = return 0
 
toInteger (Number (Integer n)) = return n
 
toInteger (Number (Double n)) = return $ truncate n
 
toInteger value =
    do num <- toNumber value
       toInteger $ Number num
 
toIntWith :: (Integer -> Int) -> Value -> Evaluate Int
toIntWith convert value =
    do num <- toNumber value
       return $ case num of
                     NaN -> 0
                     Double n | isInfinite n -> 0
                              | otherwise -> convert $ truncate n
                     Integer n -> convert n
 
toInt :: Value -> Evaluate Int
toInt = toIntWith integerToInt
    where integerToInt :: Integer -> Int
          integerToInt n =
              let intMax = floor (2**32)
                  n' = n `rem` intMax
                  in fromEnum $ if n' >= floor (2**31)
                                   then n' - intMax
                                   else n'
 
toUInt :: Value -> Evaluate Int
toUInt = toIntWith integerToUInt
    where integerToUInt :: Integer -> Int
          integerToUInt n =
              fromEnum $ n `rem` floor (2**32)
 
toUInt16 :: Value -> Evaluate Int
toUInt16 = toIntWith integerToUInt16
    where integerToUInt16 :: Integer -> Int
          integerToUInt16 n =
              fromEnum $ n `rem` floor (2**16)
 
toString :: Value -> Evaluate String
toString Void = return ""
toString Undefined = return "undefined"
toString Null = return "null"
 
toString (Boolean False) = return "false"
toString (Boolean True) = return "true"
 
toString (String string) = return string
 
toString (Number (Integer n)) = return $ show n
toString (Number (Double n)) = return $ show n
toString (Number NaN) = return "NaN"
 
toString Object { objName = name, objObject = NativeFunction { } } =
    return $ "function " ++ name ++ "() { [native code] }"
 
toString ref@Reference { } =
    do object <- getValue ref
       toString object
 
toString ref@(Ref _) =
    do object <- readRef ref
       toString object
 
toString object =
    do s <- callMethod object "toString" []
       case s of
            String s -> return s
            _ | isPrimitive s -> return $ show s
            _ -> do throw "TypeError" $ getName object ++ ".toString did not return string: " ++ show s
                    return ""
 
toSource :: Value -> Evaluate String
toSource Void = return ""
toSource Undefined = return "undefined"
toSource Null = return "null"
 
toSource (Boolean False) = return "false"
toSource (Boolean True) = return "true"
 
toSource (String string) = return $ show string
 
toSource (Number (Integer n)) = return $ show n
toSource (Number (Double n)) = return $ show n
toSource (Number NaN) = return "NaN"
 
toSource func@Object { objObject = Function { } } =
    return $ show func
    
toSource Object { objName = name, objObject = NativeFunction { } } =
    return $ "function " ++ name ++ "() { [native code] }"
 
toSource ref@Reference { } =
    do object <- getValue ref
       toSource object
 
toSource ref@(Ref _) =
    do object <- readRef ref
       toSource object
 
toSource object =
    toString =<< callMethod object "toSource" []
 
toObject :: Value -> Evaluate Value
toObject Undefined =
    throw "TypeError" "undefined cannot be converted to object"
 
toObject Null =
    throw "TypeError" "null cannot be converted to object"
 
toObject num@(Number _) =
    do klass <- getVar "Number"
       object <- makeRef =<< construct klass []
       modifyValue object $ setObjValue num
       return object
 
toObject str@(String _) =
    do klass <- getVar "String"
       object <- makeRef =<< construct klass []
       modifyValue object $ setObjValue str
       return object
 
toObject x = return x