Skip to content

Instantly share code, notes, and snippets.

@fdcastel
Last active March 30, 2016 07:27
Show Gist options
  • Save fdcastel/5a88332d61572947deb3 to your computer and use it in GitHub Desktop.
Save fdcastel/5a88332d61572947deb3 to your computer and use it in GitHub Desktop.
Fable Plugin to keep integer arithmetic in JavaScript
namespace Fable.Plugins
#r "../../build/fable/bin/Fable.exe"
open Fable.AST
open Fable.AST.Fable
open Fable.FSharp2Fable
type RandomPlugin() =
interface IReplacePlugin with
member x.TryReplace com (info: Fable.ApplyInfo) =
match info.ownerFullName with
| "Microsoft.FSharp.Core.ExtraTopLevelOperators"
| "Microsoft.FSharp.Core.Operators" ->
let patternFor t =
match t with
| PrimitiveType (Number kind) ->
match kind with
| Int8 -> Some "($0 + 0x80 & 0xFF) - 0x80"
| UInt8 -> Some "$0 & 0xFF"
| Int16 -> Some "($0 + 0x8000 & 0xFFFF) - 0x8000"
| UInt16 -> Some "$0 & 0xFFFF"
| Int32 -> Some "($0 + 0x80000000 >>> 0) - 0x80000000"
| UInt32 -> Some "$0 >>> 0"
| _ -> None
| _ -> None
let applyMask t args =
match patternFor t with
| Some pattern ->
pattern
|> Fable.Replacements.Util.emit info <| args
|> Some
| _ -> None
match info.methodName with
| "sbyte"
| "byte"
| "int8"
| "uint8"
| "int16"
| "uint16"
| "int"
| "int32"
| "uint"
| "uint32"
| "~~~"
| "~-"
| "~+" ->
if info.args.Length <> 1 then
failwithf "Unexpected arg count for '%s'" info.methodName
applyMask info.returnType info.args
| "+"
| "-"
| "*"
| "/"
| "%"
| "<<<"
| ">>>"
| "&&&"
| "|||"
| "^^^" ->
if info.args.Length <> 2 then
failwithf "Unexpected arg count for %s" info.methodName
match Fable.Replacements.Util.applyOp com info info.args info.methodName with
| Some expr -> applyMask info.returnType [expr]
| _ -> None
| _ -> None
| _ -> None
@fdcastel
Copy link
Author

Great tips! Working on it.

Also, I did somehow manage to completely miss the part you said about Babel managing the precedence order of operators. I see now you clearly state it in docs/plugins.md.

I know... I know... "More sleep, less coffee!" :)

@fdcastel
Copy link
Author

Second version. Now with Alfonso's suggestions and handling signed types.

@fdcastel
Copy link
Author

Third version. Fix a problem with signed int32.

& 0xFFFFFFFF preserves the signal (hence, does nothing :) ). Now uses >>> 0 to convert to unsigned.

Source: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

@fdcastel
Copy link
Author

Fourth version. Adds support to Microsoft.FSharp.Core.ExtraTopLevelOperators.int8/uint8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment