Skip to content

Commit 1b6d00b

Browse files
committed
✨ Include parsed value for float literals
1 parent 29eaaeb commit 1b6d00b

File tree

15 files changed

+181
-42
lines changed

15 files changed

+181
-42
lines changed

compiler-core/src/ast.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::analyse::Inferred;
1515
use crate::bit_array;
1616
use crate::build::{ExpressionPosition, Located, Target, module_erlang_name};
1717
use crate::exhaustiveness::CompiledCase;
18-
use crate::parse::SpannedString;
18+
use crate::parse::{NotNan, SpannedString};
1919
use crate::type_::error::VariableOrigin;
2020
use crate::type_::expression::{Implementations, Purity};
2121
use crate::type_::printer::Names;
@@ -2319,6 +2319,7 @@ pub enum Pattern<Type> {
23192319
Float {
23202320
location: SrcSpan,
23212321
value: EcoString,
2322+
float_value: NotNan,
23222323
},
23232324

23242325
String {

compiler-core/src/ast/constant.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum Constant<T, RecordTag> {
1616
Float {
1717
location: SrcSpan,
1818
value: EcoString,
19+
float_value: NotNan,
1920
},
2021

2122
String {

compiler-core/src/ast/typed.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::*;
66
use crate::{
77
build::ExpressionPosition,
88
exhaustiveness::CompiledCase,
9+
parse::NotNan,
910
type_::{HasType, Type, ValueConstructorVariant, bool},
1011
};
1112

@@ -22,6 +23,7 @@ pub enum TypedExpr {
2223
location: SrcSpan,
2324
type_: Arc<Type>,
2425
value: EcoString,
26+
float_value: NotNan,
2527
},
2628

2729
String {

compiler-core/src/ast/untyped.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use vec1::Vec1;
22

3+
use crate::parse::NotNan;
4+
35
use super::*;
46

57
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -13,6 +15,7 @@ pub enum UntypedExpr {
1315
Float {
1416
location: SrcSpan,
1517
value: EcoString,
18+
float_value: NotNan,
1619
},
1720

1821
String {

compiler-core/src/ast/visit.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ where
774774
location,
775775
type_,
776776
value,
777+
float_value: _,
777778
} => v.visit_typed_expr_float(location, type_, value),
778779
TypedExpr::String {
779780
location,
@@ -1568,7 +1569,11 @@ where
15681569
value,
15691570
int_value: _,
15701571
} => v.visit_typed_pattern_int(location, value),
1571-
Pattern::Float { location, value } => v.visit_typed_pattern_float(location, value),
1572+
Pattern::Float {
1573+
location,
1574+
value,
1575+
float_value: _,
1576+
} => v.visit_typed_pattern_float(location, value),
15721577
Pattern::String { location, value } => v.visit_typed_pattern_string(location, value),
15731578
Pattern::Variable {
15741579
location,

compiler-core/src/ast_folder.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
UntypedUseAssignment, Use, UseAssignment,
1818
},
1919
build::Target,
20+
parse::NotNan,
2021
type_::error::VariableOrigin,
2122
};
2223

@@ -258,7 +259,11 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
258259
value,
259260
int_value,
260261
} => self.fold_int(location, value, int_value),
261-
UntypedExpr::Float { location, value } => self.fold_float(location, value),
262+
UntypedExpr::Float {
263+
location,
264+
value,
265+
float_value,
266+
} => self.fold_float(location, value, float_value),
262267
UntypedExpr::String { location, value } => self.fold_string(location, value),
263268

264269
UntypedExpr::Block {
@@ -714,8 +719,17 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
714719
}
715720
}
716721

717-
fn fold_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedExpr {
718-
UntypedExpr::Float { location, value }
722+
fn fold_float(
723+
&mut self,
724+
location: SrcSpan,
725+
value: EcoString,
726+
float_value: NotNan,
727+
) -> UntypedExpr {
728+
UntypedExpr::Float {
729+
location,
730+
value,
731+
float_value,
732+
}
719733
}
720734

721735
fn fold_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedExpr {
@@ -937,7 +951,11 @@ pub trait UntypedConstantFolder {
937951
int_value,
938952
} => self.fold_constant_int(location, value, int_value),
939953

940-
Constant::Float { location, value } => self.fold_constant_float(location, value),
954+
Constant::Float {
955+
location,
956+
value,
957+
float_value,
958+
} => self.fold_constant_float(location, value, float_value),
941959

942960
Constant::String { location, value } => self.fold_constant_string(location, value),
943961

@@ -998,8 +1016,17 @@ pub trait UntypedConstantFolder {
9981016
}
9991017
}
10001018

1001-
fn fold_constant_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedConstant {
1002-
Constant::Float { location, value }
1019+
fn fold_constant_float(
1020+
&mut self,
1021+
location: SrcSpan,
1022+
value: EcoString,
1023+
float_value: NotNan,
1024+
) -> UntypedConstant {
1025+
Constant::Float {
1026+
location,
1027+
value,
1028+
float_value,
1029+
}
10031030
}
10041031

10051032
fn fold_constant_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedConstant {
@@ -1188,7 +1215,11 @@ pub trait PatternFolder {
11881215
int_value,
11891216
} => self.fold_pattern_int(location, value, int_value),
11901217

1191-
Pattern::Float { location, value } => self.fold_pattern_float(location, value),
1218+
Pattern::Float {
1219+
location,
1220+
value,
1221+
float_value,
1222+
} => self.fold_pattern_float(location, value, float_value),
11921223

11931224
Pattern::String { location, value } => self.fold_pattern_string(location, value),
11941225

@@ -1277,8 +1308,17 @@ pub trait PatternFolder {
12771308
}
12781309
}
12791310

1280-
fn fold_pattern_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedPattern {
1281-
Pattern::Float { location, value }
1311+
fn fold_pattern_float(
1312+
&mut self,
1313+
location: SrcSpan,
1314+
value: EcoString,
1315+
float_value: NotNan,
1316+
) -> UntypedPattern {
1317+
Pattern::Float {
1318+
location,
1319+
value,
1320+
float_value,
1321+
}
12821322
}
12831323

12841324
fn fold_pattern_string(&mut self, location: SrcSpan, value: EcoString) -> UntypedPattern {

compiler-core/src/metadata/module_decoder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
},
1313
build::Origin,
1414
line_numbers::{Character, LineNumbers},
15+
parse::NotNan,
1516
reference::{Reference, ReferenceKind, ReferenceMap},
1617
schema_capnp::{self as schema, *},
1718
type_::{
@@ -396,6 +397,7 @@ impl ModuleDecoder {
396397
Constant::Float {
397398
location: Default::default(),
398399
value: value.into(),
400+
float_value: NotNan::parse(value).expect("float value to parse as non-NaN f64"),
399401
}
400402
}
401403

compiler-core/src/metadata/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
},
1111
build::Origin,
1212
line_numbers::LineNumbers,
13+
parse::NotNan,
1314
reference::{Reference, ReferenceKind},
1415
type_::{
1516
self, Deprecation, ModuleInterface, Opaque, References, Type, TypeAliasConstructor,
@@ -1056,6 +1057,7 @@ fn constant_float() {
10561057
let module = constant_module(Constant::Float {
10571058
location: Default::default(),
10581059
value: "1.0".into(),
1060+
float_value: NotNan::ONE,
10591061
});
10601062

10611063
assert_eq!(roundtrip(&module), module);
@@ -1084,6 +1086,7 @@ fn constant_tuple() {
10841086
Constant::Float {
10851087
location: Default::default(),
10861088
value: "1.0".into(),
1089+
float_value: NotNan::ONE,
10871090
},
10881091
Constant::Tuple {
10891092
location: Default::default(),
@@ -1096,6 +1099,7 @@ fn constant_tuple() {
10961099
Constant::Float {
10971100
location: Default::default(),
10981101
value: "1.0".into(),
1102+
float_value: NotNan::ONE,
10991103
},
11001104
],
11011105
},
@@ -1146,6 +1150,7 @@ fn constant_record() {
11461150
value: Constant::Float {
11471151
location: Default::default(),
11481152
value: "0.0".into(),
1153+
float_value: NotNan::ZERO,
11491154
},
11501155
},
11511156
CallArg {

compiler-core/src/parse.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,12 @@ where
515515
}
516516
}
517517

518-
Some((start, Token::Float { value }, end)) => {
518+
Some((start, Token::Float { value, float_value }, end)) => {
519519
self.advance();
520520
UntypedExpr::Float {
521521
location: SrcSpan { start, end },
522522
value,
523+
float_value,
523524
}
524525
}
525526

@@ -1399,11 +1400,12 @@ where
13991400
int_value,
14001401
}
14011402
}
1402-
Some((start, Token::Float { value }, end)) => {
1403+
Some((start, Token::Float { value, float_value }, end)) => {
14031404
self.advance();
14041405
Pattern::Float {
14051406
location: SrcSpan { start, end },
14061407
value,
1408+
float_value,
14071409
}
14081410
}
14091411
Some((start, Token::Hash, _)) => {
@@ -3096,11 +3098,12 @@ where
30963098
}))
30973099
}
30983100

3099-
Some((start, Token::Float { value }, end)) => {
3101+
Some((start, Token::Float { value, float_value }, end)) => {
31003102
self.advance();
31013103
Ok(Some(Constant::Float {
31023104
value,
31033105
location: SrcSpan { start, end },
3106+
float_value,
31043107
}))
31053108
}
31063109

@@ -4696,3 +4699,34 @@ impl PatternPosition {
46964699
}
46974700
}
46984701
}
4702+
4703+
/// A thin f64 wrapper that does not permit NaN.
4704+
/// This allows us to implement `Eq`, which require reflexivity.
4705+
///
4706+
/// Used for gleam float literals, which cannot be NaN.
4707+
/// While there is no syntax for "infinity", float literals
4708+
/// may overflow into (possibly negative) infinity on the JS target.
4709+
#[derive(Clone, Copy, Debug, PartialEq)]
4710+
pub struct NotNan(f64);
4711+
4712+
impl NotNan {
4713+
pub const ONE: Self = NotNan(1.0);
4714+
pub const ZERO: Self = NotNan(0.0);
4715+
4716+
/// Parse from a string, returning `None` if the string
4717+
/// is not a valid f64 or the float is `NaN``
4718+
pub fn parse(value: &str) -> Option<Self> {
4719+
value
4720+
.replace("_", "")
4721+
.parse::<f64>()
4722+
.ok()
4723+
.filter(|f| !f.is_nan())
4724+
.map(NotNan)
4725+
}
4726+
4727+
pub fn value(&self) -> f64 {
4728+
self.0
4729+
}
4730+
}
4731+
4732+
impl Eq for NotNan {}

compiler-core/src/parse/lexer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use ecow::EcoString;
22

33
use crate::ast::SrcSpan;
4+
use crate::parse::NotNan;
45
use crate::parse::error::{LexicalError, LexicalErrorType};
56
use crate::parse::token::Token;
67
use std::char;
@@ -621,10 +622,12 @@ where
621622
value.push_str(&exponent_run);
622623
}
623624
let end_pos = self.get_pos();
625+
let float_value = NotNan::parse(&value).expect("float value to parse as non-NaN f64");
624626
Ok((
625627
start_pos,
626628
Token::Float {
627629
value: value.into(),
630+
float_value,
628631
},
629632
end_pos,
630633
))

0 commit comments

Comments
 (0)