Skip to content

Commit

Permalink
Fix #5729
Browse files Browse the repository at this point in the history
  • Loading branch information
gdziadkiewicz committed Jun 15, 2019
1 parent 34a1a42 commit 88957eb
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 24 deletions.
28 changes: 13 additions & 15 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2395,13 +2395,11 @@ namespace Microsoft.FSharp.Core
then p <- p + 1; -1L
else 1L

let parseOctalUInt64 (s:string) p l =
let rec parse n acc = if n < l then parse (n+1) (acc *.. 8UL +.. (let c = s.Chars(n) in if c >=... '0' && c <=... '7' then Convert.ToUInt64(c) -.. Convert.ToUInt64('0') else formatError())) else acc in
parse p 0UL

let parseBinaryUInt64 (s:string) p l =
let rec parse n acc = if n < l then parse (n+1) (acc *.. 2UL +.. (match s.Chars(n) with '0' -> 0UL | '1' -> 1UL | _ -> formatError())) else acc in
parse p 0UL
let parseBinaryUInt64 (s:string) =
Convert.ToUInt64(s, 2)

let parseOctalUInt64 (s:string) =
Convert.ToUInt64(s, 8)

let inline removeUnderscores (s:string) =
match s with
Expand All @@ -2418,8 +2416,8 @@ namespace Microsoft.FSharp.Core
if p >= l then formatError() else
match specifier with
| 'x' -> UInt32.Parse( s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture)
| 'b' -> Convert.ToUInt32(parseBinaryUInt64 s p l)
| 'o' -> Convert.ToUInt32(parseOctalUInt64 s p l)
| 'b' -> Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p)))
| 'o' -> Convert.ToUInt32(parseOctalUInt64 (s.Substring(p)))
| _ -> UInt32.Parse(s.Substring(p), NumberStyles.Integer, CultureInfo.InvariantCulture) in

let inline int32OfUInt32 (x:uint32) = (# "" x : int32 #)
Expand All @@ -2436,8 +2434,8 @@ namespace Microsoft.FSharp.Core
if p >= l then formatError() else
match Char.ToLowerInvariant(specifier) with
| 'x' -> sign * (int32OfUInt32 (Convert.ToUInt32(UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture))))
| 'b' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseBinaryUInt64 s p l)))
| 'o' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseOctalUInt64 s p l)))
| 'b' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p)))))
| 'o' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseOctalUInt64 (s.Substring(p)))))
| _ -> Int32.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture)

let ParseInt64 (s:string) =
Expand All @@ -2451,8 +2449,8 @@ namespace Microsoft.FSharp.Core
if p >= l then formatError() else
match Char.ToLowerInvariant(specifier) with
| 'x' -> sign *. Int64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture)
| 'b' -> sign *. (int64OfUInt64 (parseBinaryUInt64 s p l))
| 'o' -> sign *. (int64OfUInt64 (parseOctalUInt64 s p l))
| 'b' -> sign *. (int64OfUInt64 (parseBinaryUInt64 (s.Substring(p))))
| 'o' -> sign *. (int64OfUInt64 (parseOctalUInt64 (s.Substring(p))))
| _ -> Int64.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture)

let ParseUInt64 (s:string) : uint64 =
Expand All @@ -2465,8 +2463,8 @@ namespace Microsoft.FSharp.Core
if p >= l then formatError() else
match specifier with
| 'x' -> UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture)
| 'b' -> parseBinaryUInt64 s p l
| 'o' -> parseOctalUInt64 s p l
| 'b' -> parseBinaryUInt64 (s.Substring(p))
| 'o' -> parseOctalUInt64 (s.Substring(p))
| _ -> UInt64.Parse(s.Substring(p), NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture)


Expand Down
14 changes: 6 additions & 8 deletions src/fsharp/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,11 @@ let get0OXB (s:string) (p:byref<int>) l =

let formatError() = raise (new System.FormatException(SR.GetString("bad format string")))

let parseBinaryUInt64 (s:string) p l =
let rec parse n acc = if n < l then parse (n+1) (acc * 2UL + (match s.[n] with '0' -> 0UL | '1' -> 1UL | _ -> formatError())) else acc
parse p 0UL
let parseBinaryUInt64 (s:string) =
Convert.ToUInt64(s, 2)

let parseOctalUInt64 (s:string) p l =
let rec parse n acc = if n < l then parse (n+1) (acc * 8UL + (let c = s.[n] in if c >= '0' && c <= '7' then Convert.ToUInt64 c - Convert.ToUInt64 '0' else formatError())) else acc
parse p 0UL
let parseOctalUInt64 (s:string) =
Convert.ToUInt64(s, 8)

let removeUnderscores (s:string) =
match s with
Expand All @@ -91,8 +89,8 @@ let parseInt32 (s:string) =
match Char.ToLower(specifier,CultureInfo.InvariantCulture) with
#endif
| 'x' -> sign * (int32 (Convert.ToUInt32(UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture))))
| 'b' -> sign * (int32 (Convert.ToUInt32(parseBinaryUInt64 s p l)))
| 'o' -> sign * (int32 (Convert.ToUInt32(parseOctalUInt64 s p l)))
| 'b' -> sign * (int32 (Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p)))))
| 'o' -> sign * (int32 (Convert.ToUInt32(parseOctalUInt64 (s.Substring(p)))))
| _ -> Int32.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture)

let lexemeTrimRightToInt32 args lexbuf n =
Expand Down
58 changes: 57 additions & 1 deletion tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,47 @@ type LanguagePrimitivesModule() =
let resultValue = LanguagePrimitives.ParseInt64 "0"
Assert.AreEqual(0L, resultValue)


CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "9223372036854775808" |> ignore)

CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseInt64 "" |> ignore)

CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseInt64 null |> ignore)


[<Test>]
member this.ParseBinaryInt64() =
let resultValue = LanguagePrimitives.ParseInt64 "0b1100100"
Assert.AreEqual(typeof<int64>, resultValue.GetType())
Assert.AreEqual(100L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "-0b101100011010001010111100001011101100010100000000000000000"
Assert.AreEqual(-100000000000000000L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "0b1111111010011100101110101000011110100010011101100000000000000000"
Assert.AreEqual(-100000000000000000L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "0b0"
Assert.AreEqual(0L, resultValue)

CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "0b10000000000000000000000000000000000000000000000000000000000000000" |> ignore)

[<Test>]
member this.ParseOctalInt64() =
let resultValue = LanguagePrimitives.ParseInt64 "0o144"
Assert.AreEqual(typeof<int64>, resultValue.GetType())
Assert.AreEqual(100L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "-0o5432127413542400000"
Assert.AreEqual(-100000000000000000L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "0o1772345650364235400000"
Assert.AreEqual(-100000000000000000L, resultValue)

let resultValue = LanguagePrimitives.ParseInt64 "0o0"
Assert.AreEqual(0L, resultValue)

CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "0o2000000000000000000000" |> ignore)

[<Test>]
member this.ParseUInt32() =
let resultValue = LanguagePrimitives.ParseUInt32 "100"
Expand All @@ -444,9 +481,28 @@ type LanguagePrimitivesModule() =
Assert.AreEqual(100UL, resultValue)

CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "-1" |> ignore)
CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "18446744073709551616" |> ignore)

CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseUInt64 null |> ignore)

[<Test>]
member this.ParseBinaryUInt64() =
let resultValue = LanguagePrimitives.ParseUInt64 "0b1100100"
Assert.AreEqual(typeof<uint64>, resultValue.GetType())
Assert.AreEqual(100UL, resultValue)

CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseUInt64 "-0b1" |> ignore)
CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "0b10000000000000000000000000000000000000000000000000000000000000000" |> ignore)

[<Test>]
member this.ParseOctalUInt64() =
let resultValue = LanguagePrimitives.ParseUInt64 "0o144"
Assert.AreEqual(typeof<uint64>, resultValue.GetType())
Assert.AreEqual(100UL, resultValue)

CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseUInt64 "-0o1" |> ignore)
CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "0o2000000000000000000000" |> ignore)

[<Test>]
member this.ParseStringViaConversionOps() =
let s : string = null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// #Regression #Conformance #LexicalAnalysis #Constants


// Verify compile error for signed literals which are MaxSize + 1, MaxSize - 1
// All of these should cause compiler errors

//<Expects id="FS1147" status="error">This number is outside the allowable range for 32-bit signed integers</Expects>
//<Expects id="FS1149" status="error">This number is outside the allowable range for 64-bit signed integers</Expects>

let int64Bin65bits = 0b1_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L
let int64Octal65bits = 0o2_000_000_000_000_000_000_000L
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
SOURCE=E_MaxLiterals01.fs # E_MaxLiterals01.fs
SOURCE=E_MaxLiterals02.fs # E_MaxLiterals02.fs
SOURCE=E_MaxLiterals03.fs # E_MaxLiterals03.fs
SOURCE=E_MaxLiterals04.fs # E_MaxLiterals04.fs

SOURCE=BigNums01.fs # BigNums01.fs

Expand Down

0 comments on commit 88957eb

Please sign in to comment.