Skip to content

Commit 9f4d292

Browse files
committed
Add binary literal (ref: elm#2248)
1 parent 12f7bd2 commit 9f4d292

File tree

7 files changed

+392
-215
lines changed

7 files changed

+392
-215
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
module NumericSeparators exposing (main)
2+
3+
import Html exposing (div, table, td, text, tr)
4+
import Html.Attributes exposing (style)
5+
6+
7+
ints : List ( String, Int )
8+
ints =
9+
[ ( "2_000", 2_000 )
10+
, ( "42_000_000", 42_000_000 )
11+
]
12+
13+
14+
floats : List ( String, Float )
15+
floats =
16+
[ ( "111_000.602", 111_000.602 )
17+
, ( "1_000.4_205", 1_000.4_205 )
18+
, ( "0.000_1", 0.000_1 )
19+
, ( "0.000_000_1", 0.000_000_1 )
20+
]
21+
22+
23+
hexadecimals : List ( String, Int )
24+
hexadecimals =
25+
[ ( "0x1F_2A", 0x1F_2A )
26+
, ( "0xDEADBEEF", 0xDEADBEEF )
27+
, ( "0xDE_AD_BE_EF", 0xDE_AD_BE_EF )
28+
]
29+
30+
binaries : List ( String, Int )
31+
binaries =
32+
[ ( "0b1010", 0b1010 )
33+
, ( "0b01010110_00111000", 0b01010110_00111000 )
34+
, ( "0b0101_0110_0011_1000", 0b0101_0110_0011_1000 )
35+
]
36+
37+
38+
tableRow : (a -> String) -> ( String, a ) -> Html.Html msg
39+
tableRow toString ( label, value ) =
40+
tr []
41+
[ td [ style "min-width" "150px", style "padding" "7px" ] [ text label ]
42+
, td [ style "min-width" "150px", style "padding" "7px" ] [ text (toString value) ]
43+
]
44+
45+
46+
main =
47+
div
48+
[ style "width" "100%"
49+
, style "width" "100%"
50+
, style "display" "flex"
51+
, style "justify-content" "center"
52+
, style "align-item" "center"
53+
]
54+
[ table
55+
[ style "margin" "150px"
56+
, style "padding" "20px"
57+
]
58+
(List.map (tableRow String.fromInt) ints
59+
++ List.map (tableRow String.fromFloat) floats
60+
++ List.map (tableRow String.fromInt) hexadecimals
61+
++ List.map (tableRow String.fromInt) binaries
62+
)
63+
]

examples/src/Underscores.guida

Lines changed: 0 additions & 56 deletions
This file was deleted.

src/Compiler/Parse/Number.elm

Lines changed: 112 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Compiler.Parse.Number exposing
88

99
import Compiler.AST.Utils.Binop as Binop
1010
import Compiler.Parse.Primitives as P exposing (Col, Row)
11-
import Compiler.Parse.SyntaxVersion as SyntaxVersion exposing (SyntaxVersion)
11+
import Compiler.Parse.SyntaxVersion as SV exposing (SyntaxVersion)
1212
import Compiler.Parse.Variable as Var
1313
import Compiler.Reporting.Error.Syntax as E
1414

@@ -49,7 +49,7 @@ number syntaxVersion toExpectation toError =
4949
word =
5050
charAtPos pos src
5151
in
52-
if word == '_' && isGuida syntaxVersion then
52+
if word == '_' && syntaxVersion == SV.Guida then
5353
P.Cerr row col (toError E.NumberNoLeadingOrTrailingUnderscores)
5454

5555
else if not (isDecimalDigit word) then
@@ -102,8 +102,9 @@ number syntaxVersion toExpectation toError =
102102

103103
parsed : Maybe Float
104104
parsed =
105-
if isGuida syntaxVersion then
106-
String.replace "_" "" raw |> String.toFloat
105+
if syntaxVersion == SV.Guida then
106+
String.replace "_" "" raw
107+
|> String.toFloat
107108

108109
else
109110
String.toFloat raw
@@ -155,7 +156,7 @@ chompInt syntaxVersion src pos end n =
155156
else if word == 'e' || word == 'E' then
156157
chompExponent syntaxVersion src (pos + 1) end
157158

158-
else if isGuida syntaxVersion && word == '_' then
159+
else if word == '_' && syntaxVersion == SV.Guida then
159160
chompUnderscore_ syntaxVersion src pos end n
160161

161162
else if isDirtyEnd src pos end word then
@@ -255,7 +256,7 @@ chompFraction syntaxVersion src pos end n =
255256
nextWord =
256257
charAtPos pos1 src
257258
in
258-
if isGuida syntaxVersion && nextWord == '_' then
259+
if nextWord == '_' && syntaxVersion == SV.Guida then
259260
Err_ (pos + 1) E.NumberNoUnderscoresAdjacentToDecimalOrExponent
260261

261262
else if isDecimalDigit nextWord then
@@ -279,7 +280,7 @@ chompFractionHelp syntaxVersion src pos end =
279280
if isDecimalDigit word then
280281
chompFractionHelp syntaxVersion src (pos + 1) end
281282

282-
else if isGuida syntaxVersion && word == '_' then
283+
else if word == '_' && syntaxVersion == SV.Guida then
283284
if (pos + 1) == end then
284285
Err_ pos E.NumberNoLeadingOrTrailingUnderscores
285286

@@ -326,7 +327,7 @@ chompExponent syntaxVersion src pos end =
326327
if isDecimalDigit word then
327328
chompExponentHelp syntaxVersion src (pos + 1) end
328329

329-
else if isGuida syntaxVersion && word == '_' then
330+
else if word == '_' && syntaxVersion == SV.Guida then
330331
Err_ pos E.NumberNoUnderscoresAdjacentToDecimalOrExponent
331332

332333
else if word == '+' || word == '-' then
@@ -339,7 +340,7 @@ chompExponent syntaxVersion src pos end =
339340
nextWord =
340341
charAtPos pos1 src
341342
in
342-
if isGuida syntaxVersion && nextWord == '_' then
343+
if nextWord == '_' && syntaxVersion == SV.Guida then
343344
Err_ (pos + 1) E.NumberNoUnderscoresAdjacentToDecimalOrExponent
344345

345346
else if pos1 < end && isDecimalDigit nextWord then
@@ -363,7 +364,7 @@ chompExponentHelp syntaxVersion src pos end =
363364
word =
364365
charAtPos pos src
365366
in
366-
if isDecimalDigit word || (isGuida syntaxVersion && word == '_') then
367+
if isDecimalDigit word || (word == '_' && syntaxVersion == SV.Guida) then
367368
chompExponentHelp syntaxVersion src (pos + 1) end
368369

369370
else
@@ -386,12 +387,19 @@ chompZero syntaxVersion src pos end =
386387
charAtPos pos src
387388
in
388389
if word == 'x' then
389-
if isGuida syntaxVersion && charAtPos (pos + 1) src == '_' then
390+
if charAtPos (pos + 1) src == '_' && syntaxVersion == SV.Guida then
390391
Err_ (pos + 1) E.NumberNoUnderscoresAdjacentToHexadecimalPreFix
391392

392393
else
393394
chompHexInt syntaxVersion src (pos + 1) end
394395

396+
else if word == 'b' && syntaxVersion == SV.Guida then
397+
if charAtPos (pos + 1) src == '_' then
398+
Err_ (pos + 1) E.NumberNoUnderscoresAdjacentToBinaryPreFix
399+
400+
else
401+
chompBinInt src (pos + 1) end
402+
395403
else if word == '.' then
396404
chompFraction syntaxVersion src pos end 0
397405

@@ -424,6 +432,25 @@ chompHexInt syntaxVersion src pos end =
424432
OkInt newPos answer
425433

426434

435+
chompBinInt : String -> Int -> Int -> Outcome
436+
chompBinInt src pos end =
437+
let
438+
( newPos, answer ) =
439+
chompBin src pos end
440+
in
441+
if answer == -4 then
442+
Err_ (newPos + 1) E.NumberNoConsecutiveUnderscores
443+
444+
else if answer == -3 then
445+
Err_ newPos E.NumberNoLeadingOrTrailingUnderscores
446+
447+
else if answer < 0 then
448+
Err_ newPos E.NumberBinDigit
449+
450+
else
451+
OkInt newPos answer
452+
453+
427454

428455
-- CHOMP HEX
429456

@@ -474,7 +501,7 @@ stepHex syntaxVersion src pos end word acc =
474501
else if 'A' <= word && word <= 'F' then
475502
16 * acc + 10 + (Char.toCode word - Char.toCode 'A')
476503

477-
else if isGuida syntaxVersion && '_' == word then
504+
else if word == '_' && syntaxVersion == SV.Guida then
478505
let
479506
nextWord : Char
480507
nextWord =
@@ -505,6 +532,78 @@ stepHex syntaxVersion src pos end word acc =
505532

506533

507534

535+
-- CHOMP BIN
536+
537+
538+
chompBin : String -> Int -> Int -> ( Int, Int )
539+
chompBin src pos end =
540+
chompBinHelp src pos end -1 0
541+
542+
543+
chompBinHelp : String -> Int -> Int -> Int -> Int -> ( Int, Int )
544+
chompBinHelp src pos end answer accumulator =
545+
if pos >= end then
546+
( pos, answer )
547+
548+
else
549+
let
550+
newAnswer : Int
551+
newAnswer =
552+
stepBin src pos end (charAtPos pos src) accumulator
553+
in
554+
if newAnswer < 0 then
555+
( pos
556+
, if newAnswer == -1 then
557+
answer
558+
559+
else if newAnswer == -3 then
560+
-3
561+
562+
else if newAnswer == -4 then
563+
-4
564+
565+
else
566+
-2
567+
)
568+
569+
else
570+
chompBinHelp src (pos + 1) end newAnswer newAnswer
571+
572+
573+
stepBin : String -> Int -> Int -> Char -> Int -> Int
574+
stepBin src pos end word acc =
575+
if '0' <= word && word <= '1' then
576+
2 * acc + (Char.toCode word - Char.toCode '0')
577+
578+
else if word == '_' then
579+
let
580+
nextWord : Char
581+
nextWord =
582+
charAtPos (pos + 1) src
583+
in
584+
if nextWord == '_' then
585+
-4
586+
587+
else
588+
let
589+
validNextWord : Bool
590+
validNextWord =
591+
'0' <= nextWord && nextWord <= '1'
592+
in
593+
if pos + 1 == end || not validNextWord then
594+
-3
595+
596+
else
597+
acc
598+
599+
else if isDirtyEnd src pos end word then
600+
-2
601+
602+
else
603+
-1
604+
605+
606+
508607
-- PRECEDENCE
509608

510609

@@ -531,7 +630,7 @@ precedence toExpectation =
531630

532631

533632

534-
-- helpers
633+
-- CHAR AT POSITION
535634

536635

537636
charAtPos : Int -> String -> Char
@@ -540,8 +639,3 @@ charAtPos pos src =
540639
|> String.uncons
541640
|> Maybe.map Tuple.first
542641
|> Maybe.withDefault ' '
543-
544-
545-
isGuida : SyntaxVersion -> Bool
546-
isGuida syntaxVersion =
547-
syntaxVersion == SyntaxVersion.Guida

src/Compiler/Reporting/Error.elm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Compiler.Data.OneOrMore as OneOrMore exposing (OneOrMore)
1313
import Compiler.Elm.ModuleName as ModuleName
1414
import Compiler.Json.Encode as E
1515
import Compiler.Nitpick.PatternMatches as P
16+
import Compiler.Parse.SyntaxVersion as SV exposing (SyntaxVersion)
1617
import Compiler.Reporting.Annotation as A
1718
import Compiler.Reporting.Doc as D
1819
import Compiler.Reporting.Error.Canonicalize as Canonicalize
@@ -62,11 +63,11 @@ type Error
6263
-- TO REPORT
6364

6465

65-
toReports : Code.Source -> Error -> NE.Nonempty Report.Report
66-
toReports source err =
66+
toReports : SyntaxVersion -> Code.Source -> Error -> NE.Nonempty Report.Report
67+
toReports syntaxVersion source err =
6768
case err of
6869
BadSyntax syntaxError ->
69-
NE.singleton (Syntax.toReport source syntaxError)
70+
NE.singleton (Syntax.toReport syntaxVersion source syntaxError)
7071

7172
BadImports errs ->
7273
NE.map (Import.toReport source) errs
@@ -152,7 +153,7 @@ moduleToDoc root { absolutePath, source, error } =
152153
let
153154
reports : NE.Nonempty Report.Report
154155
reports =
155-
toReports (Code.toSource source) error
156+
toReports (SV.fileSyntaxVersion absolutePath) (Code.toSource source) error
156157

157158
relativePath : Utils.FilePath
158159
relativePath =
@@ -197,7 +198,7 @@ toJson { name, absolutePath, source, error } =
197198
let
198199
reports : NE.Nonempty Report.Report
199200
reports =
200-
toReports (Code.toSource source) error
201+
toReports (SV.fileSyntaxVersion absolutePath) (Code.toSource source) error
201202
in
202203
E.object
203204
[ ( "path", E.string absolutePath )

0 commit comments

Comments
 (0)