-
Notifications
You must be signed in to change notification settings - Fork 30
Experiments with Type module #118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jmagaram
wants to merge
9
commits into
rescript-lang:main
Choose a base branch
from
jmagaram:Core__Type-experiments
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
d19b785
experiments with Type module
jmagaram 44a17d3
fix build error
jmagaram 7092a3c
no unsafe getters
jmagaram 0fa78c4
simplify classification helpers
jmagaram ae7400e
add unsafe variants
jmagaram 3afde76
use Obj.magic
jmagaram ad4ba6b
safe getters by property name or symbol
jmagaram 7cf180c
use %identity so most just compiles away
jmagaram 76e9f5b
remove raw, use Nullable
jmagaram File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,172 @@ | ||
// Generated by ReScript, PLEASE EDIT WITH CARE | ||
|
||
import * as Caml_option from "rescript/lib/es6/caml_option.js"; | ||
|
||
function toObjectUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toBoolUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toFloatUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toBigIntUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toStringUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toSymbolUnsafe(i) { | ||
return i; | ||
} | ||
|
||
function toFunctionUnsafe(i) { | ||
return i; | ||
} | ||
|
||
var isNull = (function(a) { return (a===null); }); | ||
|
||
var isNullOrUndefined = (function(a) { return (a===null || a===undefined); }); | ||
|
||
var isUndefined = (function(a) { return (a===undefined); }); | ||
|
||
function classify(value) { | ||
var match = Object.prototype.toString.call(value); | ||
switch (match) { | ||
case "[object Boolean]" : | ||
return { | ||
TAG: /* Bool */0, | ||
_0: value | ||
}; | ||
case "[object AsyncFunction]" : | ||
case "[object Function]" : | ||
case "[object GeneratorFunction]" : | ||
return { | ||
TAG: /* Function */4, | ||
_0: value | ||
}; | ||
case "[object Null]" : | ||
return /* Null */0; | ||
case "[object Number]" : | ||
return { | ||
TAG: /* Number */2, | ||
_0: value | ||
}; | ||
case "[object String]" : | ||
return { | ||
TAG: /* String */1, | ||
_0: value | ||
}; | ||
case "[object Symbol]" : | ||
return { | ||
TAG: /* Symbol */5, | ||
_0: value | ||
}; | ||
case "[object Undefined]" : | ||
return /* Undefined */1; | ||
default: | ||
var match = typeof value; | ||
if (match === "symbol") { | ||
return { | ||
TAG: /* Symbol */5, | ||
_0: value | ||
}; | ||
} else if (match === "boolean") { | ||
return { | ||
TAG: /* Bool */1, | ||
_0: value | ||
}; | ||
} else if (match === "string") { | ||
return { | ||
TAG: /* String */4, | ||
_0: value | ||
}; | ||
} else if (match === "function") { | ||
return { | ||
TAG: /* Function */6, | ||
_0: value | ||
}; | ||
} else if (match === "object") { | ||
if (isNull(value)) { | ||
return /* Null */1; | ||
} else { | ||
return { | ||
TAG: /* Object */3, | ||
TAG: /* Object */0, | ||
_0: value | ||
}; | ||
} | ||
} else if (match === "undefined") { | ||
return /* Undefined */0; | ||
} else if (match === "number") { | ||
return { | ||
TAG: /* Number */2, | ||
_0: value | ||
}; | ||
} else { | ||
return { | ||
TAG: /* BigInt */3, | ||
_0: value | ||
}; | ||
} | ||
} | ||
|
||
var Classify = { | ||
classify: classify | ||
}; | ||
function toObject(i) { | ||
if (typeof i === "object") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toBool(i) { | ||
if (typeof i === "boolean") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toFloat(i) { | ||
if (typeof i === "number") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toBigInt(i) { | ||
if (typeof i === "bigint") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toString(i) { | ||
if (typeof i === "string") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toSymbol(i) { | ||
if (typeof i === "symbol") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function toFunction(i) { | ||
if (typeof i === "function") { | ||
return Caml_option.some(i); | ||
} | ||
|
||
} | ||
|
||
function get(item, name) { | ||
if (isNullOrUndefined(item)) { | ||
return ; | ||
} else { | ||
return item[name]; | ||
} | ||
} | ||
|
||
function getBySymbol(item, sym) { | ||
if (isNullOrUndefined(item)) { | ||
return ; | ||
} else { | ||
return item[sym]; | ||
} | ||
} | ||
|
||
export { | ||
Classify , | ||
classify , | ||
isUndefined , | ||
isNull , | ||
isNullOrUndefined , | ||
toObject , | ||
toBool , | ||
toFloat , | ||
toBigInt , | ||
toString , | ||
toSymbol , | ||
toFunction , | ||
toObjectUnsafe , | ||
toBoolUnsafe , | ||
toFloatUnsafe , | ||
toBigIntUnsafe , | ||
toStringUnsafe , | ||
toSymbolUnsafe , | ||
toFunctionUnsafe , | ||
get , | ||
getBySymbol , | ||
} | ||
/* No side effect */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,75 @@ | ||
type t = [#undefined | #object | #boolean | #number | #bigint | #string | #symbol | #function] | ||
|
||
external typeof: 'a => t = "#typeof" | ||
|
||
module Classify = { | ||
type function | ||
type object | ||
type symbol | ||
|
||
type t = | ||
| Bool(bool) | ||
| Null | ||
| Undefined | ||
| String(string) | ||
| Number(float) | ||
| Object(object) | ||
| Function(function) | ||
| Symbol(symbol) | ||
|
||
@val external _internalClass: 'a => string = "Object.prototype.toString.call" | ||
external _asBool: 'a => bool = "%identity" | ||
external _asString: 'a => string = "%identity" | ||
external _asFloat: 'a => float = "%identity" | ||
external _asObject: 'a => object = "%identity" | ||
external _asFunction: 'a => function = "%identity" | ||
external _asSymbol: 'a => symbol = "%identity" | ||
|
||
let classify = value => { | ||
switch _internalClass(value) { | ||
| "[object Boolean]" => Bool(_asBool(value)) | ||
| "[object Null]" => Null | ||
| "[object Undefined]" => Undefined | ||
| "[object String]" => String(_asString(value)) | ||
| "[object Number]" => Number(_asFloat(value)) | ||
| "[object Function]" | ||
| "[object GeneratorFunction]" | ||
| "[object AsyncFunction]" => | ||
Function(_asFunction(value)) | ||
| "[object Symbol]" => Symbol(_asSymbol(value)) | ||
| _ => Object(_asObject(value)) | ||
type typeof = [ | ||
| #undefined | ||
| #object | ||
| #boolean | ||
| #number | ||
| #bigint | ||
| #string | ||
| #symbol | ||
| #function | ||
] | ||
|
||
external typeof: 'a => typeof = "#typeof" | ||
|
||
type unknown | ||
external toUnknown: 'a => unknown = "%identity" | ||
|
||
type object // How to use with the Object module? | ||
type function | ||
|
||
// typeof null == "object". Gotta love that! Do better here. | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#typeof_null | ||
type jsType = | ||
| Undefined | ||
| Null | ||
| Object(object) | ||
| Bool(bool) | ||
| Number(float) | ||
| BigInt(Core__BigInt.t) | ||
| String(string) | ||
| Symbol(Core__Symbol.t) | ||
| Function(function) | ||
|
||
let toObjectUnsafe = i => i->Obj.magic | ||
let toBoolUnsafe = i => i->Obj.magic | ||
let toFloatUnsafe = i => i->Obj.magic | ||
let toBigIntUnsafe = i => i->Obj.magic | ||
let toStringUnsafe = i => i->Obj.magic | ||
let toSymbolUnsafe = i => i->Obj.magic | ||
let toFunctionUnsafe = i => i->Obj.magic | ||
|
||
let isNull = %raw(`function(a) { return (a===null); }`) | ||
let isNullOrUndefined = %raw(`function(a) { return (a===null || a===undefined); }`) | ||
let isUndefined = %raw(`function(a) { return (a===undefined); }`) | ||
|
||
let classify = value => { | ||
switch typeof(value) { | ||
| #number => value->toFloatUnsafe->Number | ||
| #string => value->toStringUnsafe->String | ||
| #boolean => value->toBoolUnsafe->Bool | ||
| #undefined => Undefined | ||
| #function => value->toFunctionUnsafe->Function | ||
| #bigint => value->toBigIntUnsafe->BigInt | ||
| #symbol => value->toSymbolUnsafe->Symbol | ||
| #object => | ||
switch isNull(value) { | ||
| true => Null | ||
| false => value->toObjectUnsafe->Object | ||
} | ||
} | ||
} | ||
|
||
let toObject = i => typeof(i) === #object ? i->Obj.magic->Some : None | ||
let toBool = i => typeof(i) === #boolean ? i->Obj.magic->Some : None | ||
let toFloat = i => typeof(i) === #number ? i->Obj.magic->Some : None | ||
let toBigInt = i => typeof(i) === #bigint ? i->Obj.magic->Some : None | ||
let toString = i => typeof(i) === #string ? i->Obj.magic->Some : None | ||
let toSymbol = i => typeof(i) === #symbol ? i->Obj.magic->Some : None | ||
let toFunction = i => typeof(i) === #function ? i->Obj.magic->Some : None | ||
|
||
// throws on null or undefined | ||
@get_index external getUnsafe: ('a, string) => option<unknown> = "" | ||
@get_index external getBySymbolUnsafe: ('a, Core__Symbol.t) => option<unknown> = "" | ||
|
||
let get = (item, name) => isNullOrUndefined(item) ? None : item->getUnsafe(name) | ||
let getBySymbol = (item, sym) => isNullOrUndefined(item) ? None : item->getBySymbolUnsafe(sym) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, this isn't what I meant. These are now all just aliases of
Obj.magic
, and wherever these are used internally you can just substitute withObj.magic
directly.If you want to export them, then the externals are better because the implementation won't be hidden by the interface and consequently add a function call on every use to what should be a no-op at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the problem. I looked at the javascript and there are all these wrappers and we want it to be completely compiled away. I went back to using external %identity in both the
resi
and theres
because that results in less Js output. I find it very weird that theresi
file has implementation details likeexternal
. If theresi
just sayslet toBoolUnsafe: 'a => bool
then this is the output...In a perfect world wouldn't you be able to only use
external
in the implementation?