git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Check int values are within range in codegen
a072316Gary Burgess
examples/failing/IntOutOfRange.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith IntOutOfRange
2+
3+module Main where
4+
5+n :: Int
6+n = 35028715023
src/Language/PureScript/CodeGen/JS.hs+30−21
@@ -34,6 +34,7 @@ import qualified Data.Traversable as T (traverse)
34
34
35import Control.Arrow ((&&&))
35import Control.Arrow ((&&&))
36import Control.Monad (replicateM, forM)
36import Control.Monad (replicateM, forM)
37+import Control.Monad.Error.Class (MonadError(..))
37import Control.Monad.Reader (MonadReader, asks)
38import Control.Monad.Reader (MonadReader, asks)
38import Control.Monad.Supply.Class
39import Control.Monad.Supply.Class
39
40
@@ -43,6 +44,7 @@ import Language.PureScript.CodeGen.JS.AST as AST
43import Language.PureScript.CodeGen.JS.Common as Common
44import Language.PureScript.CodeGen.JS.Common as Common
44import Language.PureScript.CoreFn
45import Language.PureScript.CoreFn
45import Language.PureScript.Names
46import Language.PureScript.Names
47+import Language.PureScript.Errors
46import Language.PureScript.CodeGen.JS.Optimizer
48import Language.PureScript.CodeGen.JS.Optimizer
47import Language.PureScript.Options
49import Language.PureScript.Options
48import Language.PureScript.Traversals (sndM)
50import Language.PureScript.Traversals (sndM)
@@ -54,22 +56,23 @@ import System.FilePath.Posix ((</>))
54-- Generate code in the simplified Javascript intermediate representation for all declarations in a
56-- Generate code in the simplified Javascript intermediate representation for all declarations in a
55-- module.
57-- module.
56--
58--
57−moduleToJs :: forall m. (Applicative m, Monad m, MonadReader Options m, MonadSupply m)
59+moduleToJs :: forall m. (Applicative m, Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m)
58 => Module Ann -> Maybe JS -> m [JS]
60 => Module Ann -> Maybe JS -> m [JS]
59−moduleToJs (Module coms mn imps exps foreigns decls) foreign_ = do
61+moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
62+ rethrow (addHint (ErrorInModule mn)) $ do
60− jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
63+ jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
61− jsDecls <- mapM bindToJs decls
64+ jsDecls <- mapM bindToJs decls
62− optimized <- T.traverse (T.traverse optimize) jsDecls
65+ optimized <- T.traverse (T.traverse optimize) jsDecls
63− comments <- not <$> asks optionsNoComments
66+ comments <- not <$> asks optionsNoComments
64− let strict = JSStringLiteral "use strict"
67+ let strict = JSStringLiteral "use strict"
65− let header = if comments && not (null coms) then JSComment coms strict else strict
68+ let header = if comments && not (null coms) then JSComment coms strict else strict
66− let foreign' = [JSVariableIntroduction "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
69+ let foreign' = [JSVariableIntroduction "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
67− let moduleBody = header : foreign' ++ jsImports ++ concat optimized
70+ let moduleBody = header : foreign' ++ jsImports ++ concat optimized
68− let foreignExps = exps `intersect` (fst `map` foreigns)
71+ let foreignExps = exps `intersect` (fst `map` foreigns)
69− let standardExps = exps \\ foreignExps
72+ let standardExps = exps \\ foreignExps
70− let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
73+ let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
71− ++ map (runIdent &&& foreignIdent) foreignExps
74+ ++ map (runIdent &&& foreignIdent) foreignExps
72− return $ moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
75+ return $ moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
73
76
74 where
77 where
75
78
@@ -129,8 +132,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ = do
129 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
132 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
130 --
133 --
131 valueToJs :: Expr Ann -> m JS
134 valueToJs :: Expr Ann -> m JS
132− valueToJs (Literal _ l) =
135+ valueToJs (Literal (pos, _, _, _) l) =
133− literalToValueJS l
136+ maybe id rethrowWithPosition pos $ literalToValueJS l
134 valueToJs (Var (_, _, _, Just (IsConstructor _ [])) name) =
137 valueToJs (Var (_, _, _, Just (IsConstructor _ [])) name) =
135 return $ JSAccessor "value" $ qualifiedToJS id name
138 return $ JSAccessor "value" $ qualifiedToJS id name
136 valueToJs (Var (_, _, _, Just (IsConstructor _ _)) name) =
139 valueToJs (Var (_, _, _, Just (IsConstructor _ _)) name) =
@@ -207,7 +210,13 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ = do
207 iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
210 iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
208
211
209 literalToValueJS :: Literal (Expr Ann) -> m JS
212 literalToValueJS :: Literal (Expr Ann) -> m JS
210− literalToValueJS (NumericLiteral n) = return $ JSNumericLiteral n
213+ literalToValueJS (NumericLiteral (Left i)) =
214+ let minInt = -2147483648
215+ maxInt = 2147483647
216+ in if i < minInt || i > maxInt
217+ then throwError . errorMessage $ IntOutOfRange i "JavaScript" minInt maxInt
218+ else return $ JSNumericLiteral (Left i)
219+ literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral (Right n)
211 literalToValueJS (StringLiteral s) = return $ JSStringLiteral s
220 literalToValueJS (StringLiteral s) = return $ JSStringLiteral s
212 literalToValueJS (CharLiteral c) = return $ JSStringLiteral [c]
221 literalToValueJS (CharLiteral c) = return $ JSStringLiteral [c]
213 literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral b
222 literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral b
@@ -275,10 +284,10 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ = do
275 go _ _ _ = internalError "Invalid arguments to bindersToJs"
284 go _ _ _ = internalError "Invalid arguments to bindersToJs"
276
285
277 failedPatternError :: [String] -> JS
286 failedPatternError :: [String] -> JS
278− failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral errorMessage) (JSArrayLiteral $ zipWith valueError names vals)]
287+ failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral failedPatternMessage) (JSArrayLiteral $ zipWith valueError names vals)]
279
288
280− errorMessage :: String
289+ failedPatternMessage :: String
281− errorMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
290+ failedPatternMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
282
291
283 valueError :: String -> JS -> JS
292 valueError :: String -> JS -> JS
284 valueError _ l@(JSNumericLiteral _) = l
293 valueError _ l@(JSNumericLiteral _) = l
src/Language/PureScript/Errors.hs+6
@@ -146,6 +146,7 @@ data SimpleErrorMessage
146 | RedundantUnqualifiedImport ModuleName ImportDeclarationType
146 | RedundantUnqualifiedImport ModuleName ImportDeclarationType
147 | DuplicateSelectiveImport ModuleName
147 | DuplicateSelectiveImport ModuleName
148 | DuplicateImport ModuleName ImportDeclarationType (Maybe ModuleName)
148 | DuplicateImport ModuleName ImportDeclarationType (Maybe ModuleName)
149+ | IntOutOfRange Integer String Integer Integer
149 deriving (Show)
150 deriving (Show)
150
151
151-- | Error message hints, providing more detailed information about failure.
152-- | Error message hints, providing more detailed information about failure.
@@ -284,6 +285,7 @@ errorCode em = case unwrapErrorMessage em of
284 RedundantUnqualifiedImport{} -> "RedundantUnqualifiedImport"
285 RedundantUnqualifiedImport{} -> "RedundantUnqualifiedImport"
285 DuplicateSelectiveImport{} -> "DuplicateSelectiveImport"
286 DuplicateSelectiveImport{} -> "DuplicateSelectiveImport"
286 DuplicateImport{} -> "DuplicateImport"
287 DuplicateImport{} -> "DuplicateImport"
288+ IntOutOfRange{} -> "IntOutOfRange"
287
289
288
290
289-- |
291-- |
@@ -762,6 +764,10 @@ prettyPrintSingleError full level e = do
762 renderSimpleErrorMessage (DuplicateImport name imp qual) =
764 renderSimpleErrorMessage (DuplicateImport name imp qual) =
763 line $ "Duplicate import of " ++ prettyPrintImport name imp qual
765 line $ "Duplicate import of " ++ prettyPrintImport name imp qual
764
766
767+ renderSimpleErrorMessage (IntOutOfRange value backend lo hi) =
768+ paras [ line $ "Integer value " ++ show value ++ " is out of range for the " ++ backend ++ " backend."
769+ , line $ "Acceptable values fall within the range " ++ show lo ++ " to " ++ show hi ++ " (inclusive)." ]
770+
765 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
771 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
766 renderHint (ErrorUnifyingTypes t1 t2) detail =
772 renderHint (ErrorUnifyingTypes t1 t2) detail =
767 paras [ detail
773 paras [ detail
tests/support/bower.json+1−1
@@ -2,7 +2,7 @@
2 "name": "purescript-test-suite-support",
2 "name": "purescript-test-suite-support",
3 "dependencies": {
3 "dependencies": {
4 "purescript-eff": "0.1.0",
4 "purescript-eff": "0.1.0",
5− "purescript-prelude": "0.1.1",
5+ "purescript-prelude": "0.1.3",
6 "purescript-assert": "0.1.1",
6 "purescript-assert": "0.1.1",
7 "purescript-st": "0.1.0",
7 "purescript-st": "0.1.0",
8 "purescript-console": "0.1.0",
8 "purescript-console": "0.1.0",