diff --git a/CHANGELOG.md b/CHANGELOG.md index cc992beb..b8809183 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Change `Float.parseFloat` signature. Now accepts only string. https://github.com/rescript-association/rescript-core/pull/54 - Add `getExn`, `getUnsafe`, `getWithDefault`, `map`, `mapWithDefault` and `flatMap` to `Nullable`. https://github.com/rescript-association/rescript-core/pull/67 - Add `getExn`, `getUnsafe`, `getWithDefault`, `map`, `mapWithDefault` and `flatMap` to `Null`. https://github.com/rescript-association/rescript-core/pull/73 +- Add `panic`/`Error.panic` and use that where appropriate: https://github.com/rescript-association/rescript-core/pull/72 ### Documentation diff --git a/package.json b/package.json index d23f0f91..f4a3fb7b 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,9 @@ "clean": "rescript clean", "build": "rescript", "watch": "rescript build -w", - "test": "node test/PromiseTest.mjs && node test/TempTests.mjs" + "test": "node test/TestSuite.mjs && node test/TempTests.mjs" }, - "keywords": [ - "rescript" - ], + "keywords": ["rescript"], "homepage": "https://github.com/rescript-association/rescript-core", "author": "ReScript Team", "license": "MIT", diff --git a/src/Core__Error.mjs b/src/Core__Error.mjs index b9e0a7a0..e5334cf8 100644 --- a/src/Core__Error.mjs +++ b/src/Core__Error.mjs @@ -13,6 +13,10 @@ var $$TypeError = {}; var $$URIError = {}; +function panic(msg) { + throw new Error("Panic! " + msg); +} + export { $$EvalError , $$RangeError , @@ -20,5 +24,6 @@ export { $$SyntaxError , $$TypeError , $$URIError , + panic , } /* No side effect */ diff --git a/src/Core__Error.res b/src/Core__Error.res index 69e05994..788e0bdb 100644 --- a/src/Core__Error.res +++ b/src/Core__Error.res @@ -35,3 +35,5 @@ module URIError = { } external raise: t => 'a = "%raise" + +let panic = msg => make(j`Panic! $msg`)->raise diff --git a/src/Core__Error.resi b/src/Core__Error.resi index 563c6fc2..76c12c0c 100644 --- a/src/Core__Error.resi +++ b/src/Core__Error.resi @@ -155,3 +155,17 @@ if 5 > 10 { ``` */ external raise: t => 'a = "%raise" + +/** +Raises a panic exception with the given message. + +A panic exception is a native JavaScript exception that is not intended to be caught and +handled. Compared to a ReScript exception this will give a better stack trace and +debugging experience. + +## Examples +```rescript +Error.panic("Uh oh. This was unexpected!") +``` +*/ +let panic: string => 'a diff --git a/src/Core__List.mjs b/src/Core__List.mjs index 8da20a23..b9844598 100644 --- a/src/Core__List.mjs +++ b/src/Core__List.mjs @@ -4,6 +4,7 @@ import * as Curry from "rescript/lib/es6/curry.js"; import * as Belt_Array from "rescript/lib/es6/belt_Array.js"; import * as Caml_option from "rescript/lib/es6/caml_option.js"; import * as Core__Array from "./Core__Array.mjs"; +import * as Core__Error from "./Core__Error.mjs"; function head(x) { if (x) { @@ -15,11 +16,9 @@ function head(x) { function headExn(x) { if (x) { return x.hd; + } else { + return Core__Error.panic("List.headExn: list is empty"); } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; } function tail(x) { @@ -32,11 +31,9 @@ function tail(x) { function tailExn(x) { if (x) { return x.tl; + } else { + return Core__Error.panic("List.tailExn: list is empty"); } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; } function add(xs, x) { @@ -70,29 +67,24 @@ function get(x, n) { function getExn(x, n) { if (n < 0) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - var _x = x; - var _n = n; - while(true) { - var n$1 = _n; - var x$1 = _x; - if (x$1) { + return Core__Error.panic("List.getExn: n < 0"); + } else { + var _x = x; + var _n = n; + while(true) { + var n$1 = _n; + var x$1 = _x; + if (!x$1) { + return Core__Error.panic("List.nthAuxAssert: list is empty"); + } if (n$1 === 0) { return x$1.hd; } _n = n$1 - 1 | 0; _x = x$1.tl; continue ; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; + }; + } } function partitionAux(p, _cell, _precX, _precY) { diff --git a/src/Core__List.res b/src/Core__List.res index 27c248e7..7aa88386 100644 --- a/src/Core__List.res +++ b/src/Core__List.res @@ -94,7 +94,7 @@ let head = x => let headExn = x => switch x { - | list{} => raise(Not_found) + | list{} => Core__Error.panic("List.headExn: list is empty") | list{x, ..._} => x } @@ -106,7 +106,7 @@ let tail = x => let tailExn = x => switch x { - | list{} => raise(Not_found) + | list{} => Core__Error.panic("List.tailExn: list is empty") | list{_, ...t} => t } @@ -132,7 +132,7 @@ let rec nthAuxAssert = (x, n) => } else { nthAuxAssert(t, n - 1) } - | _ => raise(Not_found) + | list{} => Core__Error.panic("List.nthAuxAssert: list is empty") } let get = (x, n) => @@ -144,7 +144,7 @@ let get = (x, n) => let getExn = (x, n) => if n < 0 { - raise(Not_found) + Core__Error.panic("List.getExn: n < 0") } else { nthAuxAssert(x, n) } diff --git a/src/Core__List.resi b/src/Core__List.resi index 189083af..b97b54f5 100644 --- a/src/Core__List.resi +++ b/src/Core__List.resi @@ -82,7 +82,7 @@ List.headExn(list{}) // Raises an Error ## Exceptions -- Raises an Error if list is empty. +- Panics if list is empty. */ let headExn: t<'a> => 'a @@ -114,7 +114,7 @@ List.tailExn(list{}) // Raises an Error ## Exceptions -- Raises an Error if list is empty. +- Panics if list is empty. */ let tailExn: t<'a> => t<'a> @@ -162,7 +162,7 @@ abc->List.getExn(4) // Raises an Error ## Exceptions -- Raises an Error if `index` is larger than the length of list. +- Panics if `index` is less than 0 or larger than the length of list. */ let getExn: (t<'a>, int) => 'a diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 29ad429b..052265a2 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -2,6 +2,7 @@ import * as Curry from "rescript/lib/es6/curry.js"; import * as Caml_option from "rescript/lib/es6/caml_option.js"; +import * as Core__Error from "./Core__Error.mjs"; function filter(opt, p) { var p$1 = Curry.__1(p); @@ -22,11 +23,9 @@ function forEach(opt, f) { function getExn(x) { if (x !== undefined) { return Caml_option.valFromOption(x); + } else { + return Core__Error.panic("List.headExn: option is None"); } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; } function mapWithDefault(opt, $$default, f) { diff --git a/src/Core__Option.res b/src/Core__Option.res index 9b688647..19802440 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -41,7 +41,7 @@ let forEach = (opt, f) => forEachU(opt, (. x) => f(x)) let getExn = x => switch x { | Some(x) => x - | None => raise(Not_found) + | None => Core__Error.panic("List.headExn: option is None") } external getUnsafe: option<'a> => 'a = "%identity" diff --git a/src/Core__Option.resi b/src/Core__Option.resi index fb3c8a46..a2d348ed 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -75,7 +75,7 @@ Option.getExn(None) /* Raises an Error */ ## Exceptions -- Raises an error if `opt` is `None` +- Panics if `opt` is `None` */ let getExn: option<'a> => 'a diff --git a/src/Core__Result.mjs b/src/Core__Result.mjs index 832ab968..e8c8aba0 100644 --- a/src/Core__Result.mjs +++ b/src/Core__Result.mjs @@ -1,15 +1,14 @@ // Generated by ReScript, PLEASE EDIT WITH CARE import * as Curry from "rescript/lib/es6/curry.js"; +import * as Core__Error from "./Core__Error.mjs"; function getExn(x) { if (x.TAG === /* Ok */0) { return x._0; + } else { + return Core__Error.panic("Result.getExn: result is Error"); } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; } function mapWithDefault(opt, $$default, f) { diff --git a/src/Core__Result.res b/src/Core__Result.res index 51032a64..56f3d8fb 100644 --- a/src/Core__Result.res +++ b/src/Core__Result.res @@ -27,7 +27,7 @@ type t<'a, 'b> = result<'a, 'b> = Ok('a) | Error('b) let getExn = x => switch x { | Ok(x) => x - | Error(_) => raise(Not_found) + | Error(_) => Core__Error.panic("Result.getExn: result is Error") } let mapWithDefaultU = (opt, default, f) => diff --git a/src/Core__Result.resi b/src/Core__Result.resi index d1e6636d..6eeebdd3 100644 --- a/src/Core__Result.resi +++ b/src/Core__Result.resi @@ -55,6 +55,10 @@ type t<'a, 'b> = result<'a, 'b> = Ok('a) | Error('b) Result.getExn(Result.Error("Invalid data")) /* raises exception */ ``` + +## Exceptions + +- Panics if `res` is `Error(_)` */ let getExn: t<'a, 'b> => 'a diff --git a/src/RescriptCore.mjs b/src/RescriptCore.mjs index 7706a777..334f6e2d 100644 --- a/src/RescriptCore.mjs +++ b/src/RescriptCore.mjs @@ -1,5 +1,6 @@ // Generated by ReScript, PLEASE EDIT WITH CARE +import * as Core__Error from "./Core__Error.mjs"; var $$Array; @@ -93,6 +94,8 @@ var List; var Result; +var panic = Core__Error.panic; + export { $$Array , Console , @@ -140,5 +143,6 @@ export { $$Option , List , Result , + panic , } /* No side effect */ diff --git a/src/RescriptCore.res b/src/RescriptCore.res index 7cd77db2..d76bcde0 100644 --- a/src/RescriptCore.res +++ b/src/RescriptCore.res @@ -65,3 +65,5 @@ type null<+'a> = Js.null<'a> type undefined<+'a> = Js.undefined<'a> type nullable<+'a> = Js.nullable<'a> + +let panic = Core__Error.panic diff --git a/test/ErrorTests.mjs b/test/ErrorTests.mjs new file mode 100644 index 00000000..a9af7afb --- /dev/null +++ b/test/ErrorTests.mjs @@ -0,0 +1,39 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Test from "./Test.mjs"; +import * as Js_exn from "rescript/lib/es6/js_exn.js"; +import * as RescriptCore from "../src/RescriptCore.mjs"; +import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js"; + +function panicTest(param) { + var caught; + try { + caught = RescriptCore.panic("uh oh"); + } + catch (raw_err){ + var err = Caml_js_exceptions.internalToOCamlException(raw_err); + if (err.RE_EXN_ID === Js_exn.$$Error) { + caught = err._1.message; + } else { + throw err; + } + } + Test.run([ + [ + "ErrorTests.res", + 8, + 22, + 43 + ], + "Should resolve test" + ], caught, (function (prim0, prim1) { + return prim0 === prim1; + }), "Panic! uh oh"); +} + +panicTest(undefined); + +export { + panicTest , +} +/* Not a pure module */ diff --git a/test/ErrorTests.res b/test/ErrorTests.res new file mode 100644 index 00000000..07dcc078 --- /dev/null +++ b/test/ErrorTests.res @@ -0,0 +1,11 @@ +open RescriptCore + +let panicTest = () => { + let caught = try panic("uh oh") catch { + | Exn.Error(err) => Error.message(err) + } + + Test.run(__POS_OF__("Should resolve test"), caught, \"==", Some("Panic! uh oh")) +} + +panicTest() diff --git a/test/TestSuite.mjs b/test/TestSuite.mjs new file mode 100644 index 00000000..bde8356a --- /dev/null +++ b/test/TestSuite.mjs @@ -0,0 +1,35 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as ErrorTests from "./ErrorTests.mjs"; +import * as PromiseTest from "./PromiseTest.mjs"; + +var TestError = PromiseTest.TestError; + +var fail = PromiseTest.fail; + +var equal = PromiseTest.equal; + +var Creation = PromiseTest.Creation; + +var ThenChaining = PromiseTest.ThenChaining; + +var Rejection = PromiseTest.Rejection; + +var Catching = PromiseTest.Catching; + +var Concurrently = PromiseTest.Concurrently; + +var panicTest = ErrorTests.panicTest; + +export { + TestError , + fail , + equal , + Creation , + ThenChaining , + Rejection , + Catching , + Concurrently , + panicTest , +} +/* ErrorTests Not a pure module */ diff --git a/test/TestSuite.res b/test/TestSuite.res new file mode 100644 index 00000000..c2ae6367 --- /dev/null +++ b/test/TestSuite.res @@ -0,0 +1,2 @@ +include PromiseTest +include ErrorTests