Skip to content

Commit e1b6e6f

Browse files
fruno-bulaxlpil
authored andcommitted
✨ Include parsed value for float literals
1 parent f9fd43e commit e1b6e6f

File tree

15 files changed

+183
-38
lines changed

15 files changed

+183
-38
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::{LiteralFloatValue, SpannedString};
1919
use crate::type_::error::VariableOrigin;
2020
use crate::type_::expression::{Implementations, Purity};
2121
use crate::type_::printer::Names;
@@ -2356,6 +2356,7 @@ pub enum Pattern<Type> {
23562356
Float {
23572357
location: SrcSpan,
23582358
value: EcoString,
2359+
float_value: LiteralFloatValue,
23592360
},
23602361

23612362
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: LiteralFloatValue,
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::LiteralFloatValue,
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: LiteralFloatValue,
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::LiteralFloatValue;
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: LiteralFloatValue,
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::LiteralFloatValue,
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: LiteralFloatValue,
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: LiteralFloatValue,
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: LiteralFloatValue,
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: 3 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::LiteralFloatValue,
1516
reference::{Reference, ReferenceKind, ReferenceMap},
1617
schema_capnp::{self as schema, *},
1718
type_::{
@@ -396,6 +397,8 @@ impl ModuleDecoder {
396397
Constant::Float {
397398
location: Default::default(),
398399
value: value.into(),
400+
float_value: LiteralFloatValue::parse(value)
401+
.expect("float value to parse as non-NaN f64"),
399402
}
400403
}
401404

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::LiteralFloatValue,
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: LiteralFloatValue::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: LiteralFloatValue::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: LiteralFloatValue::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: LiteralFloatValue::ZERO,
11491154
},
11501155
},
11511156
CallArg {

compiler-core/src/parse.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,12 @@ where
517517
}
518518
}
519519

520-
Some((start, Token::Float { value }, end)) => {
520+
Some((start, Token::Float { value, float_value }, end)) => {
521521
self.advance();
522522
UntypedExpr::Float {
523523
location: SrcSpan { start, end },
524524
value,
525+
float_value,
525526
}
526527
}
527528

@@ -1401,11 +1402,12 @@ where
14011402
int_value,
14021403
}
14031404
}
1404-
Some((start, Token::Float { value }, end)) => {
1405+
Some((start, Token::Float { value, float_value }, end)) => {
14051406
self.advance();
14061407
Pattern::Float {
14071408
location: SrcSpan { start, end },
14081409
value,
1410+
float_value,
14091411
}
14101412
}
14111413
Some((start, Token::Hash, _)) => {
@@ -3117,11 +3119,12 @@ where
31173119
}))
31183120
}
31193121

3120-
Some((start, Token::Float { value }, end)) => {
3122+
Some((start, Token::Float { value, float_value }, end)) => {
31213123
self.advance();
31223124
Ok(Some(Constant::Float {
31233125
value,
31243126
location: SrcSpan { start, end },
3127+
float_value,
31253128
}))
31263129
}
31273130

@@ -4717,3 +4720,34 @@ impl PatternPosition {
47174720
}
47184721
}
47194722
}
4723+
4724+
/// A thin f64 wrapper that does not permit NaN.
4725+
/// This allows us to implement `Eq`, which require reflexivity.
4726+
///
4727+
/// Used for gleam float literals, which cannot be NaN.
4728+
/// While there is no syntax for "infinity", float literals
4729+
/// may overflow into (possibly negative) infinity on the JS target.
4730+
#[derive(Clone, Copy, Debug, PartialEq)]
4731+
pub struct LiteralFloatValue(f64);
4732+
4733+
impl LiteralFloatValue {
4734+
pub const ONE: Self = LiteralFloatValue(1.0);
4735+
pub const ZERO: Self = LiteralFloatValue(0.0);
4736+
4737+
/// Parse from a string, returning `None` if the string
4738+
/// is not a valid f64 or the float is `NaN``
4739+
pub fn parse(value: &str) -> Option<Self> {
4740+
value
4741+
.replace("_", "")
4742+
.parse::<f64>()
4743+
.ok()
4744+
.filter(|f| !f.is_nan())
4745+
.map(LiteralFloatValue)
4746+
}
4747+
4748+
pub fn value(&self) -> f64 {
4749+
self.0
4750+
}
4751+
}
4752+
4753+
impl Eq for LiteralFloatValue {}

compiler-core/src/parse/lexer.rs

Lines changed: 4 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::LiteralFloatValue;
45
use crate::parse::error::{LexicalError, LexicalErrorType};
56
use crate::parse::token::Token;
67
use std::char;
@@ -621,10 +622,13 @@ where
621622
value.push_str(&exponent_run);
622623
}
623624
let end_pos = self.get_pos();
625+
let float_value =
626+
LiteralFloatValue::parse(&value).expect("float value to parse as non-NaN f64");
624627
Ok((
625628
start_pos,
626629
Token::Float {
627630
value: value.into(),
631+
float_value,
628632
},
629633
end_pos,
630634
))

0 commit comments

Comments
 (0)